home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / gfx / misc / gnuplot-3.7src.lha / gnuplot-3.7src / gnuplot-3.7.lha / gnuplot-3.7 / set.c < prev    next >
C/C++ Source or Header  |  1998-12-08  |  92KB  |  3,165 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: set.c,v 1.68 1998/06/22 12:24:54 ddenholm Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - set.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37.  
  38. /*
  39.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  40.  * Added user-specified bases for log scaling.
  41.  */
  42.  
  43. #include "plot.h"
  44. #include "stdfn.h"
  45. #include "setshow.h"
  46. #include "national.h"
  47.  
  48. #define DEF_FORMAT   "%g"    /* default format for tic mark labels */
  49. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  50.  
  51. /*
  52.  * global variables to hold status of 'set' options
  53.  *
  54.  * IMPORTANT NOTE:
  55.  * ===============
  56.  * If you change the default values of one of the variables below, or if
  57.  * you add another global variable, make sure that the change you make is
  58.  * done in reset_command() as well (if that makes sense).
  59.  */
  60.  
  61. TBOOLEAN autoscale_r = DTRUE;
  62. TBOOLEAN autoscale_t = DTRUE;
  63. TBOOLEAN autoscale_u = DTRUE;
  64. TBOOLEAN autoscale_v = DTRUE;
  65. TBOOLEAN autoscale_x = DTRUE;
  66. TBOOLEAN autoscale_y = DTRUE;
  67. TBOOLEAN autoscale_z = DTRUE;
  68. TBOOLEAN autoscale_x2 = DTRUE;
  69. TBOOLEAN autoscale_y2 = DTRUE;
  70. TBOOLEAN autoscale_lt = DTRUE;
  71. TBOOLEAN autoscale_lu = DTRUE;
  72. TBOOLEAN autoscale_lv = DTRUE;
  73. TBOOLEAN autoscale_lx = DTRUE;
  74. TBOOLEAN autoscale_ly = DTRUE;
  75. TBOOLEAN autoscale_lz = DTRUE;
  76. TBOOLEAN multiplot = FALSE;
  77.  
  78. double boxwidth = -1.0;        /* box width (automatic) */
  79. TBOOLEAN clip_points = FALSE;
  80. TBOOLEAN clip_lines1 = TRUE;
  81. TBOOLEAN clip_lines2 = FALSE;
  82. struct lp_style_type border_lp = { 0, -2, 0, 1.0, 1.0 };
  83. int draw_border = 31;
  84. TBOOLEAN draw_surface = TRUE;
  85. char dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1] = { "x", "y" };
  86. char default_font[MAX_ID_LEN+1] = "";    /* Entry font added by DJL */
  87. char xformat[MAX_ID_LEN+1] = DEF_FORMAT;
  88. char yformat[MAX_ID_LEN+1] = DEF_FORMAT;
  89. char zformat[MAX_ID_LEN+1] = DEF_FORMAT;
  90. char x2format[MAX_ID_LEN+1] = DEF_FORMAT;
  91. char y2format[MAX_ID_LEN+1] = DEF_FORMAT;
  92.  
  93. /* do formats look like times - use FIRST_X_AXIS etc as index
  94.  * - never saved or shown ...
  95.  */
  96. #if AXIS_ARRAY_SIZE != 10
  97. # error error in initialiser for format_is_numeric
  98. #endif
  99.  
  100. int format_is_numeric[AXIS_ARRAY_SIZE] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
  101.  
  102. enum PLOT_STYLE data_style = POINTSTYLE;
  103. enum PLOT_STYLE func_style = LINES;
  104. double bar_size = 1.0;
  105. struct lp_style_type work_grid = { 0, GRID_OFF, 0, 1.0, 1.0 };
  106. struct lp_style_type grid_lp   = { 0, -1, 0, 1.0, 1.0 };
  107. struct lp_style_type mgrid_lp  = { 0, -1, 0, 1.0, 1.0 };
  108. double polar_grid_angle = 0;    /* nonzero means a polar grid */
  109. int key = -1;            /* default position */
  110. struct position key_user_pos;    /* user specified position for key */
  111. TBOOLEAN key_reverse = FALSE;    /* reverse text & sample ? */
  112. struct lp_style_type key_box = { 0, -3, 0, 1.0, 1.0 };        /* -3 = no linetype */
  113. double key_swidth = 4.0;
  114. double key_vert_factor = 1.0;
  115. double key_width_fix = 0.0;
  116. TBOOLEAN is_log_x = FALSE;
  117. TBOOLEAN is_log_y = FALSE;
  118. TBOOLEAN is_log_z = FALSE;
  119. TBOOLEAN is_log_x2 = FALSE;
  120. TBOOLEAN is_log_y2 = FALSE;
  121. double base_log_x = 0.0;
  122. double base_log_y = 0.0;
  123. double base_log_z = 0.0;
  124. double base_log_x2 = 0.0;
  125. double base_log_y2 = 0.0;
  126. double log_base_log_x = 0.0;
  127. double log_base_log_y = 0.0;
  128. double log_base_log_z = 0.0;
  129. double log_base_log_x2 = 0.0;
  130. double log_base_log_y2 = 0.0;
  131. FILE *gpoutfile;
  132. char *outstr = NULL;        /* means "STDOUT" */
  133. TBOOLEAN parametric = FALSE;
  134. double pointsize = 1.0;
  135. int encoding;
  136. char *encoding_names[] = { "default", "iso_8859_1", "cp437", "cp850", NULL };
  137. TBOOLEAN polar = FALSE;
  138. TBOOLEAN hidden3d = FALSE;
  139. TBOOLEAN label_contours = TRUE;    /* different linestyles are used for contours when set */
  140. char contour_format[32] = "%8.3g";    /* format for contour key entries */
  141. int angles_format = ANGLES_RADIANS;
  142. double ang2rad = 1.0;        /* 1 or pi/180, tracking angles_format */
  143. int mapping3d = MAP3D_CARTESIAN;
  144. int samples = SAMPLES;        /* samples is always equal to samples_1 */
  145. int samples_1 = SAMPLES;
  146. int samples_2 = SAMPLES;
  147. int iso_samples_1 = ISO_SAMPLES;
  148. int iso_samples_2 = ISO_SAMPLES;
  149. float xsize = 1.0;        /* scale factor for size */
  150. float ysize = 1.0;        /* scale factor for size */
  151. float zsize = 1.0;        /* scale factor for size */
  152. float xoffset = 0.0;        /* x origin */
  153. float yoffset = 0.0;        /* y origin */
  154. float aspect_ratio = 0.0;    /* don't attempt to force it */
  155. float surface_rot_z = 30.0;    /* Default 3d transform. */
  156. float surface_rot_x = 60.0;
  157. float surface_scale = 1.0;
  158. float surface_zscale = 1.0;
  159. struct termentry *term = NULL;    /* unknown */
  160. char term_options[MAX_LINE_LEN+1] = "";
  161. label_struct title = { "", 0.0, 0.0, "" };
  162. label_struct timelabel = { "", 0.0, 0.0, "" };
  163. label_struct xlabel = { "", 0.0, 0.0, "" };
  164. label_struct ylabel = { "", 0.0, 0.0, "" };
  165. label_struct zlabel = { "", 0.0, 0.0, "" };
  166. label_struct x2label = { "", 0.0, 0.0, "" };
  167. label_struct y2label = { "", 0.0, 0.0, "" };
  168.  
  169. int timelabel_rotate = FALSE;
  170. int timelabel_bottom = TRUE;
  171. char key_title[MAX_LINE_LEN+1] = "";
  172. double rmin = -0.0;
  173. double rmax = 10.0;
  174. double tmin = -5.0;
  175. double tmax = 5.0;
  176. double umin = -5.0;
  177. double umax = 5.0;
  178. double vmin = -5.0;
  179. double vmax = 5.0;
  180. double xmin = -10.0;
  181. double xmax = 10.0;
  182. double ymin = -10.0;
  183. double ymax = 10.0;
  184. double zmin = -10.0;
  185. double zmax = 10.0;
  186. double x2min = -10.0;
  187. double x2max = 10.0;
  188. double y2min = -10.0;
  189. double y2max = 10.0;
  190. double loff = 0.0;
  191. double roff = 0.0;
  192. double toff = 0.0;
  193. double boff = 0.0;
  194. int draw_contour = CONTOUR_NONE;
  195. int contour_pts = 5;
  196. int contour_kind = CONTOUR_KIND_LINEAR;
  197. int contour_order = 4;
  198. int contour_levels = 5;
  199. double zero = ZERO;        /* zero threshold, not 0! */
  200. int levels_kind = LEVELS_AUTO;
  201. double levels_list[MAX_DISCRETE_LEVELS];    /* storage for z levels to draw contours at */
  202.  
  203. int dgrid3d_row_fineness = 10;
  204. int dgrid3d_col_fineness = 10;
  205. int dgrid3d_norm_value = 1;
  206. TBOOLEAN dgrid3d = FALSE;
  207.  
  208. struct lp_style_type xzeroaxis = { 0, -3, 0, 1.0, 1.0 };
  209. struct lp_style_type yzeroaxis = { 0, -3, 0, 1.0, 1.0 };
  210. struct lp_style_type x2zeroaxis = { 0, -3, 0, 1.0, 1.0 };
  211. struct lp_style_type y2zeroaxis = { 0, -3, 0, 1.0, 1.0 };
  212.  
  213. /* perhaps make these into an array one day */
  214.  
  215. int xtics = TICS_ON_BORDER | TICS_MIRROR;
  216. int ytics = TICS_ON_BORDER | TICS_MIRROR;
  217. int ztics = TICS_ON_BORDER;    /* no mirror by default for ztics */
  218. int x2tics = NO_TICS;
  219. int y2tics = NO_TICS;
  220.  
  221. TBOOLEAN rotate_xtics = FALSE;
  222. TBOOLEAN rotate_ytics = FALSE;
  223. TBOOLEAN rotate_ztics = FALSE;
  224. TBOOLEAN rotate_x2tics = FALSE;
  225. TBOOLEAN rotate_y2tics = FALSE;
  226.  
  227. int range_flags[AXIS_ARRAY_SIZE];    /* = {0,0,...} */
  228.  
  229. int mxtics = MINI_DEFAULT;
  230. int mytics = MINI_DEFAULT;
  231. int mztics = MINI_DEFAULT;
  232. int mx2tics = MINI_DEFAULT;
  233. int my2tics = MINI_DEFAULT;
  234.  
  235. double mxtfreq = 10;        /* # intervals between major */
  236. double mytfreq = 10;        /* tic marks */
  237. double mztfreq = 10;
  238. double mx2tfreq = 10;
  239. double my2tfreq = 10;
  240.  
  241. double ticscale = 1.0;        /* scale factor for tic mark */
  242. double miniticscale = 0.5;    /* and for minitics */
  243.  
  244. float ticslevel = 0.5;
  245.  
  246. struct ticdef xticdef = { TIC_COMPUTED };
  247. struct ticdef yticdef = { TIC_COMPUTED };
  248. struct ticdef zticdef = { TIC_COMPUTED };
  249. struct ticdef x2ticdef = { TIC_COMPUTED };
  250. struct ticdef y2ticdef = { TIC_COMPUTED };
  251.  
  252. TBOOLEAN tic_in = TRUE;
  253.  
  254. struct text_label *first_label = NULL;
  255. struct arrow_def *first_arrow = NULL;
  256. struct linestyle_def *first_linestyle = NULL;
  257.  
  258. int lmargin = -1;        /* space between left edge and xleft in chars (-1: computed) */
  259. int bmargin = -1;        /* space between bottom and ybot in chars (-1: computed) */
  260. int rmargin = -1;        /* space between right egde and xright in chars (-1: computed) */
  261. int tmargin = -1;        /* space between top egde and ytop in chars (-1: computed) */
  262.  
  263. /* string representing missing values in ascii datafiles */
  264. char *missing_val = NULL;
  265.  
  266. /* date&time language conversions */
  267.                  /* extern struct dtconv *dtc; *//* HBB 980317: unused and not defined anywhere !? */
  268.  
  269. /*** other things we need *****/
  270.  
  271. /* input data, parsing variables */
  272.  
  273. extern TBOOLEAN is_3d_plot;
  274.  
  275. /* From plot2d.c */
  276. extern struct curve_points *first_plot;
  277. /* From plot3d.c */
  278. extern struct surface_points *first_3dplot;
  279.  
  280. int key_hpos = TRIGHT;        /* place for curve-labels, corner or outside */
  281. int key_vpos = TTOP;        /* place for curve-labels, corner or below */
  282. int key_just = JRIGHT;        /* alignment of key labels, left or right */
  283.  
  284. #ifndef TIMEFMT
  285. #define TIMEFMT "%d/%m/%y\n%H:%M"
  286. #endif
  287. /* format for date/time for reading time in datafile */
  288. char timefmt[25] = TIMEFMT;
  289.  
  290. /* array of datatypes (x in 0,y in 1,z in 2,..(rtuv)) */
  291. /* not sure how rtuv come into it ?
  292.  * oh well, make first six compatible with FIRST_X_AXIS, etc
  293.  */
  294. int datatype[DATATYPE_ARRAY_SIZE];
  295.  
  296. char cur_locale[MAX_ID_LEN+1] = "C";
  297.  
  298. /* not set or shown directly, but controlled by 'set locale'
  299.  * defined in national.h
  300.  */
  301.  
  302. char full_month_names[12][32] =
  303. { FMON01, FMON02, FMON03, FMON04, FMON05, FMON06, FMON07, FMON08, FMON09, FMON10, FMON11, FMON12 };
  304. char abbrev_month_names[12][8] =
  305. { AMON01, AMON02, AMON03, AMON04, AMON05, AMON06, AMON07, AMON08, AMON09, AMON10, AMON11, AMON12 };
  306.  
  307. char full_day_names[7][32] =
  308. { FDAY0, FDAY1, FDAY2, FDAY3, FDAY4, FDAY5, FDAY6 };
  309. char abbrev_day_names[7][8] =
  310. { ADAY0, ADAY1, ADAY2, ADAY3, ADAY4, ADAY5, ADAY6 };
  311.  
  312.  
  313.  
  314. /******** Local functions ********/
  315. static void get_position __PROTO((struct position * pos));
  316. static void get_position_type __PROTO((enum position_type * type, int *axes));
  317. static void set_xyzlabel __PROTO((label_struct * label));
  318. static void set_label __PROTO((void));
  319. static void set_nolabel __PROTO((void));
  320. static void set_arrow __PROTO((void));
  321. static void set_noarrow __PROTO((void));
  322. static void load_tics __PROTO((int axis, struct ticdef * tdef));
  323. static void load_tic_user __PROTO((int axis, struct ticdef * tdef));
  324. static void free_marklist __PROTO((struct ticmark * list));
  325. static void load_tic_series __PROTO((int axis, struct ticdef * tdef));
  326. static void load_offsets __PROTO((double *a, double *b, double *c, double *d));
  327. static void delete_label __PROTO((struct text_label * prev, struct text_label * this));
  328. static int assign_label_tag __PROTO((void));
  329. static void delete_arrow __PROTO((struct arrow_def * prev, struct arrow_def * this));
  330. static int assign_arrow_tag __PROTO((void));
  331. static void set_linestyle __PROTO((void));
  332. static void set_nolinestyle __PROTO((void));
  333. static int assign_linestyle_tag __PROTO((void));
  334. static void delete_linestyle __PROTO((struct linestyle_def * prev, struct linestyle_def * this));
  335. static TBOOLEAN set_one __PROTO((void));
  336. static TBOOLEAN set_two __PROTO((void));
  337. static TBOOLEAN set_three __PROTO((void));
  338. static int looks_like_numeric __PROTO((char *));
  339. static void set_lp_properties __PROTO((struct lp_style_type * arg, int allow_points, int lt, int pt, double lw, double ps));
  340. static void reset_lp_properties __PROTO((struct lp_style_type *arg));
  341. static void set_locale __PROTO((char *));
  342.  
  343. static int set_tic_prop __PROTO((int *TICS, int *MTICS, double *FREQ,
  344.      struct ticdef * tdef, int AXIS, TBOOLEAN * ROTATE, char *tic_side));
  345.  
  346.  
  347. /* following code segment appears over and over again */
  348. #define GET_NUM_OR_TIME(store,axis) \
  349. do{if ( datatype[axis] == TIME && isstring(c_token) ) { \
  350.     char ss[80]; struct tm tm; \
  351.     quote_str(ss,c_token, 80); ++c_token; \
  352.     if (gstrptime(ss,timefmt,&tm)) store = (double) gtimegm(&tm); else store = 0;\
  353.    } else {\
  354.     struct value value; \
  355.     store = real(const_express(&value));\
  356.   }}while(0)
  357.  
  358. /******** The 'reset' command ********/
  359. void reset_command()
  360. {
  361.     register struct curve_points *f_p = first_plot;
  362.     register struct surface_points *f_3dp = first_3dplot;
  363.  
  364.     c_token++;
  365.     first_plot = NULL;
  366.     first_3dplot = NULL;
  367.     cp_free(f_p);
  368.     sp_free(f_3dp);
  369.     /* delete arrows */
  370.     while (first_arrow != NULL)
  371.     delete_arrow((struct arrow_def *) NULL, first_arrow);
  372.     /* delete labels */
  373.     while (first_label != NULL)
  374.     delete_label((struct text_label *) NULL, first_label);
  375.     /* delete linestyles */
  376.     while (first_linestyle != NULL)
  377.     delete_linestyle((struct linestyle_def *) NULL, first_linestyle);
  378.     strcpy(dummy_var[0], "x");
  379.     strcpy(dummy_var[1], "y");
  380.     strcpy(title.text, "");
  381.     strcpy(xlabel.text, "");
  382.     strcpy(ylabel.text, "");
  383.     strcpy(zlabel.text, "");
  384.     strcpy(x2label.text, "");
  385.     strcpy(y2label.text, "");
  386.     *title.font = 0;
  387.     *xlabel.font = 0;
  388.     *ylabel.font = 0;
  389.     *zlabel.font = 0;
  390.     *x2label.font = 0;
  391.     *y2label.font = 0;
  392.     strcpy(key_title, "");
  393.     strcpy(timefmt, TIMEFMT);
  394.     strcpy(xformat, DEF_FORMAT);
  395.     strcpy(yformat, DEF_FORMAT);
  396.     strcpy(zformat, DEF_FORMAT);
  397.     strcpy(x2format, DEF_FORMAT);
  398.     strcpy(y2format, DEF_FORMAT);
  399.     format_is_numeric[FIRST_X_AXIS] = format_is_numeric[SECOND_X_AXIS] = 1;
  400.     format_is_numeric[FIRST_Y_AXIS] = format_is_numeric[SECOND_Y_AXIS] = 1;
  401.     format_is_numeric[FIRST_Z_AXIS] = format_is_numeric[SECOND_Z_AXIS] = 1;
  402.     autoscale_r = DTRUE;
  403.     autoscale_t = DTRUE;
  404.     autoscale_u = DTRUE;
  405.     autoscale_v = DTRUE;
  406.     autoscale_x = DTRUE;
  407.     autoscale_y = DTRUE;
  408.     autoscale_z = DTRUE;
  409.     autoscale_x2 = DTRUE;
  410.     autoscale_y2 = DTRUE;
  411.     autoscale_lt = DTRUE;
  412.     autoscale_lu = DTRUE;
  413.     autoscale_lv = DTRUE;
  414.     autoscale_lx = DTRUE;
  415.     autoscale_ly = DTRUE;
  416.     autoscale_lz = DTRUE;
  417.     boxwidth = -1.0;
  418.     clip_points = FALSE;
  419.     clip_lines1 = TRUE;
  420.     clip_lines2 = FALSE;
  421.     set_lp_properties(&border_lp, 0, -2, 0, 1.0, 1.0);
  422.     draw_border = 31;
  423.     draw_surface = TRUE;
  424.     data_style = POINTSTYLE;
  425.     func_style = LINES;
  426.     bar_size = 1.0;
  427.     set_lp_properties(&work_grid, 0, GRID_OFF, 0, 0.5, 1.0);
  428.     set_lp_properties(&grid_lp, 0, -1, 0, 0.5, 1.0);
  429.     set_lp_properties(&mgrid_lp, 0, -1, 0, 0.5, 1.0);
  430.     polar_grid_angle = 0;
  431.     key = -1;
  432.     is_log_x = FALSE;
  433.     is_log_y = FALSE;
  434.     is_log_z = FALSE;
  435.     is_log_x2 = FALSE;
  436.     is_log_y2 = FALSE;
  437.     base_log_x = 0.0;
  438.     base_log_y = 0.0;
  439.     base_log_z = 0.0;
  440.     base_log_x2 = 0.0;
  441.     base_log_y2 = 0.0;
  442.     log_base_log_x = 0.0;
  443.     log_base_log_y = 0.0;
  444.     log_base_log_z = 0.0;
  445.     log_base_log_x2 = 0.0;
  446.     log_base_log_y2 = 0.0;
  447.     parametric = FALSE;
  448.     polar = FALSE;
  449.     hidden3d = FALSE;
  450.     label_contours = TRUE;
  451.     strcpy(contour_format, "%8.3g");
  452.     angles_format = ANGLES_RADIANS;
  453.     ang2rad = 1.0;
  454.     mapping3d = MAP3D_CARTESIAN;
  455.     samples = SAMPLES;
  456.     samples_1 = SAMPLES;
  457.     samples_2 = SAMPLES;
  458.     iso_samples_1 = ISO_SAMPLES;
  459.     iso_samples_2 = ISO_SAMPLES;
  460.     xsize = 1.0;
  461.     ysize = 1.0;
  462.     zsize = 1.0;
  463.     xoffset = 0.0;
  464.     yoffset = 0.0;
  465.     aspect_ratio = 0.0;        /* dont force it */
  466.     surface_rot_z = 30.0;
  467.     surface_rot_x = 60.0;
  468.     surface_scale = 1.0;
  469.     surface_zscale = 1.0;
  470.     *timelabel.text = 0;
  471.     timelabel.xoffset = 0;
  472.     timelabel.yoffset = 0;
  473.     *timelabel.font = 0;
  474.     timelabel_rotate = FALSE;
  475.     timelabel_bottom = TRUE;
  476.     title.xoffset = 0;
  477.     title.yoffset = 0;
  478.     xlabel.xoffset = 0;
  479.     xlabel.yoffset = 0;
  480.     ylabel.xoffset = 0;
  481.     ylabel.yoffset = 0;
  482.     zlabel.xoffset = 0;
  483.     zlabel.yoffset = 0;
  484.     x2label.xoffset = 0;
  485.     x2label.yoffset = 0;
  486.     y2label.xoffset = 0;
  487.     y2label.yoffset = 0;
  488.     rmin = -0.0;
  489.     rmax = 10.0;
  490.     tmin = -5.0;
  491.     tmax = 5.0;
  492.     umin = -5.0;
  493.     umax = 5.0;
  494.     vmin = -5.0;
  495.     vmax = 5.0;
  496.     xmin = -10.0;
  497.     xmax = 10.0;
  498.     ymin = -10.0;
  499.     ymax = 10.0;
  500.     zmin = -10.0;
  501.     zmax = 10.0;
  502.     x2min = -10.0;
  503.     x2max = 10.0;
  504.     y2min = -10.0;
  505.     y2max = 10.0;
  506.     memset(range_flags, 0, sizeof(range_flags));    /* all = 0 */
  507.  
  508.     loff = 0.0;
  509.     roff = 0.0;
  510.     toff = 0.0;
  511.     boff = 0.0;
  512.     draw_contour = CONTOUR_NONE;
  513.     contour_pts = 5;
  514.     contour_kind = CONTOUR_KIND_LINEAR;
  515.     contour_order = 4;
  516.     contour_levels = 5;
  517.     zero = ZERO;
  518.     levels_kind = LEVELS_AUTO;
  519.     dgrid3d_row_fineness = 10;
  520.     dgrid3d_col_fineness = 10;
  521.     dgrid3d_norm_value = 1;
  522.     dgrid3d = FALSE;
  523.     set_lp_properties(&xzeroaxis, 0, -3, 0, 1.0, 1.0);
  524.     set_lp_properties(&yzeroaxis, 0, -3, 0, 1.0, 1.0);
  525.     set_lp_properties(&x2zeroaxis, 0, -3, 0, 1.0, 1.0);
  526.     set_lp_properties(&y2zeroaxis, 0, -3, 0, 1.0, 1.0);
  527.     xtics =
  528.     ytics = TICS_ON_BORDER | TICS_MIRROR;
  529.     ztics = TICS_ON_BORDER;    /* no mirror by default */
  530.     x2tics = NO_TICS;
  531.     y2tics = NO_TICS;
  532.     mxtics =
  533.     mytics =
  534.     mztics =
  535.     mx2tics =
  536.     my2tics = MINI_DEFAULT;
  537.     mxtfreq = 10.0;
  538.     mytfreq = 10.0;
  539.     mztfreq = 10.0;
  540.     mx2tfreq = 10.0;
  541.     my2tfreq = 10.0;
  542.     ticscale = 1.0;
  543.     miniticscale = 0.5;
  544.     ticslevel = 0.5;
  545.     xticdef.type = TIC_COMPUTED;
  546.     yticdef.type = TIC_COMPUTED;
  547.     zticdef.type = TIC_COMPUTED;
  548.     x2ticdef.type = TIC_COMPUTED;
  549.     y2ticdef.type = TIC_COMPUTED;
  550.     tic_in = TRUE;
  551.     lmargin =
  552.     bmargin =
  553.     rmargin =
  554.     tmargin = -1;        /* autocomputed */
  555.     key_hpos = TRIGHT;
  556.     key_vpos = TTOP;
  557.     key_just = JRIGHT;
  558.     key_reverse = FALSE;
  559.     set_lp_properties(&key_box, 0, -3, 0, 1.0, 1.0);
  560.     key_swidth = 4;
  561.     key_vert_factor = 1;
  562.     key_width_fix = 0;
  563.     datatype[FIRST_X_AXIS] = FALSE;
  564.     datatype[FIRST_Y_AXIS] = FALSE;
  565.     datatype[FIRST_Z_AXIS] = FALSE;
  566.     datatype[SECOND_X_AXIS] = FALSE;
  567.     datatype[SECOND_Y_AXIS] = FALSE;
  568.     datatype[SECOND_Z_AXIS] = FALSE;
  569.     datatype[R_AXIS] = FALSE;
  570.     datatype[T_AXIS] = FALSE;
  571.     datatype[U_AXIS] = FALSE;
  572.     datatype[V_AXIS] = FALSE;
  573.  
  574.     pointsize = 1.0;
  575.     encoding = ENCODING_DEFAULT;
  576.  
  577.     set_locale("C");        /* default */
  578. }
  579.  
  580. /******** The 'set' command ********/
  581. void set_command()
  582. {
  583.     static char GPFAR setmess[] = "\
  584. valid set options:  [] = choose one, {} means optional\n\n\
  585. \t'angles',  '{no}arrow',  '{no}autoscale',  'bars',  '{no}border',\n\
  586. \t'boxwidth', '{no}clabel', '{no}clip', 'cntrparam', '{no}contour',\n\
  587. \t'data style',  '{no}dgrid3d',  'dummy',  'encoding',  'format',\n\
  588. \t'function style',   '{no}grid',   '{no}hidden3d',   'isosamples',\n\
  589. \t'{no}key', '{no}label', '{no}linestyle', 'locale', '{no}logscale',\n\
  590. \t'[blrt]margin', 'mapping', 'missing', '{no}multiplot', 'offsets',\n\
  591. \t'origin', 'output', '{no}parametric', 'pointsize', '{no}polar',\n\
  592. \t'[rtuv]range',  'samples',  'size',  '{no}surface',  'terminal',\n\
  593. \t'tics',  'ticscale',  'ticslevel',  '{no}timestamp',  'timefmt',\n\
  594. \t'title', 'view', '[xyz]{2}data', '[xyz]{2}label', '[xyz]{2}range',\n\
  595. \t'{no}{m}[xyz]{2}tics', '[xyz]{2}[md]tics', '{no}{[xyz]{2}}zeroaxis',\n\
  596. \t'zero'";
  597.  
  598.     c_token++;
  599.  
  600.     if (!set_one() && !set_two() && !set_three())
  601.     int_error(setmess, c_token);
  602. }
  603.  
  604. /* return TRUE if a command match, FALSE if not */
  605. static TBOOLEAN
  606. set_one()
  607. {
  608. /* save on replication with a macro */
  609. #define PROCESS_AUTO_LETTER(AUTO, STRING,MIN,MAX) \
  610. else if (equals(c_token, STRING))       { AUTO = DTRUE; ++c_token; } \
  611. else if (almost_equals(c_token, MIN)) { AUTO |= 1;    ++c_token; } \
  612. else if (almost_equals(c_token, MAX)) { AUTO |= 2;    ++c_token; }
  613.  
  614.     if (almost_equals(c_token, "ar$row")) {
  615.     c_token++;
  616.     set_arrow();
  617.     } else if (almost_equals(c_token, "noar$row")) {
  618.     c_token++;
  619.     set_noarrow();
  620.     } else if (almost_equals(c_token, "au$toscale")) {
  621.     c_token++;
  622.     if (END_OF_COMMAND) {
  623.         autoscale_r = autoscale_t = autoscale_x = autoscale_y = autoscale_z = autoscale_x2 = autoscale_y2 = DTRUE;
  624.     } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
  625.         autoscale_x = autoscale_y = DTRUE;
  626.         c_token++;
  627.     }
  628.     PROCESS_AUTO_LETTER(autoscale_r, "r", "rmi$n", "rma$x")
  629.     PROCESS_AUTO_LETTER(autoscale_t, "t", "tmi$n", "tma$x")
  630.     PROCESS_AUTO_LETTER(autoscale_u, "u", "umi$n", "uma$x")
  631.     PROCESS_AUTO_LETTER(autoscale_v, "v", "vmi$n", "vma$x")
  632.     PROCESS_AUTO_LETTER(autoscale_x, "x", "xmi$n", "xma$x")
  633.     PROCESS_AUTO_LETTER(autoscale_y, "y", "ymi$n", "yma$x")
  634.     PROCESS_AUTO_LETTER(autoscale_z, "z", "zmi$n", "zma$x")
  635.     PROCESS_AUTO_LETTER(autoscale_x2, "x2", "x2mi$n", "x2ma$x")
  636.     PROCESS_AUTO_LETTER(autoscale_y2, "y2", "y2mi$n", "y2ma$x")
  637.     else
  638.         int_error("Invalid range", c_token);
  639.     } else if (almost_equals(c_token,"noau$toscale")) {
  640.     c_token++;
  641.     if (END_OF_COMMAND) {
  642.         autoscale_r = autoscale_t = autoscale_x = autoscale_y = autoscale_z = FALSE;
  643.     } else if (equals(c_token, "xy") || equals(c_token, "tyx")) {
  644.         autoscale_x = autoscale_y = FALSE;
  645.         c_token++;
  646.     } else if (equals(c_token, "r")) {
  647.         autoscale_r = FALSE;
  648.         c_token++;
  649.     } else if (equals(c_token, "t")) {
  650.         autoscale_t = FALSE;
  651.         c_token++;
  652.     } else if (equals(c_token, "u")) {
  653.         autoscale_u = FALSE;
  654.         c_token++;
  655.     } else if (equals(c_token, "v")) {
  656.         autoscale_v = FALSE;
  657.         c_token++;
  658.     } else if (equals(c_token, "x")) {
  659.         autoscale_x = FALSE;
  660.         c_token++;
  661.     } else if (equals(c_token, "y")) {
  662.         autoscale_y = FALSE;
  663.         c_token++;
  664.     } else if (equals(c_token, "z")) {
  665.         autoscale_z = FALSE;
  666.         c_token++;
  667.     }
  668.     } else if (almost_equals(c_token,"nobor$der")) {
  669.     draw_border = 0;
  670.     c_token++;
  671.     }
  672.     else if (almost_equals(c_token,"box$width")) {
  673.     struct value a;
  674.     c_token++;
  675.     if (END_OF_COMMAND)
  676.         boxwidth = -1.0;
  677.     else
  678. /*              if((boxwidth = real(const_express(&a))) != -2.0)*/
  679. /*                      boxwidth = magnitude(const_express(&a));*/
  680.         boxwidth = real(const_express(&a));
  681.     } else if (almost_equals(c_token,"c$lip")) {
  682.     c_token++;
  683.     if (END_OF_COMMAND)
  684.         /* assuming same as points */
  685.         clip_points = TRUE;
  686.     else if (almost_equals(c_token, "p$oints"))
  687.         clip_points = TRUE;
  688.     else if (almost_equals(c_token, "o$ne"))
  689.         clip_lines1 = TRUE;
  690.     else if (almost_equals(c_token, "t$wo"))
  691.         clip_lines2 = TRUE;
  692.     else
  693.         int_error("expecting 'points', 'one', or 'two'", c_token);
  694.     c_token++;
  695.     } else if (almost_equals(c_token,"noc$lip")) {
  696.     c_token++;
  697.     if (END_OF_COMMAND) {
  698.         /* same as all three */
  699.         clip_points = FALSE;
  700.         clip_lines1 = FALSE;
  701.         clip_lines2 = FALSE;
  702.     } else if (almost_equals(c_token, "p$oints"))
  703.         clip_points = FALSE;
  704.     else if (almost_equals(c_token, "o$ne"))
  705.         clip_lines1 = FALSE;
  706.     else if (almost_equals(c_token, "t$wo"))
  707.         clip_lines2 = FALSE;
  708.     else
  709.         int_error("expecting 'points', 'one', or 'two'", c_token);
  710.     c_token++;
  711.     } else if (almost_equals(c_token,"hi$dden3d")) {
  712. #ifdef LITE
  713.     printf(" Hidden Line Removal Not Supported in LITE version\n");
  714.     c_token++;
  715. #else
  716.     /* HBB 970618: new parsing engine for hidden3d options */
  717.     set_hidden3doptions();
  718.     hidden3d = TRUE;
  719. #endif /* LITE */
  720.     } else if (almost_equals(c_token,"nohi$dden3d")) {
  721. #ifdef LITE
  722.     printf(" Hidden Line Removal Not Supported in LITE version\n");
  723. #else
  724.     hidden3d = FALSE;
  725. #endif /* LITE */
  726.     c_token++;
  727.     } else if (almost_equals(c_token,"cla$bel")) {
  728.     label_contours = TRUE;
  729.     c_token++;
  730.     if (isstring(c_token))
  731.         quote_str(contour_format, c_token++, 30);
  732.     } else if (almost_equals(c_token,"nocla$bel")) {
  733.     label_contours = FALSE;
  734.     c_token++;
  735.     } else if (almost_equals(c_token,"ma$pping3d")) {
  736.     c_token++;
  737.     if (END_OF_COMMAND)
  738.         /* assuming same as points */
  739.         mapping3d = MAP3D_CARTESIAN;
  740.     else if (almost_equals(c_token, "ca$rtesian"))
  741.         mapping3d = MAP3D_CARTESIAN;
  742.     else if (almost_equals(c_token, "s$pherical"))
  743.         mapping3d = MAP3D_SPHERICAL;
  744.     else if (almost_equals(c_token, "cy$lindrical"))
  745.         mapping3d = MAP3D_CYLINDRICAL;
  746.     else
  747.         int_error("expecting 'cartesian', 'spherical', or 'cylindrical'", c_token);
  748.     c_token++;
  749.     } else if (almost_equals(c_token,"co$ntour")) {
  750.     c_token++;
  751.     if (END_OF_COMMAND)
  752.         /* assuming same as points */
  753.         draw_contour = CONTOUR_BASE;
  754.     else {
  755.         if (almost_equals(c_token, "ba$se"))
  756.          draw_contour = CONTOUR_BASE;
  757.         else if (almost_equals(c_token, "s$urface"))
  758.         draw_contour = CONTOUR_SRF;
  759.         else if (almost_equals(c_token, "bo$th"))
  760.         draw_contour = CONTOUR_BOTH;
  761.         else
  762.         int_error("expecting 'base', 'surface', or 'both'", c_token);
  763.         c_token++;
  764.     }
  765.     } else if (almost_equals(c_token,"noco$ntour")) {
  766.     c_token++;
  767.     draw_contour = CONTOUR_NONE;
  768.     } else if (almost_equals(c_token,"cntrp$aram")) {
  769.     struct value a;
  770.  
  771.     c_token++;
  772.     if (END_OF_COMMAND) {
  773.         /* assuming same as defaults */
  774.         contour_pts = 5;
  775.         contour_kind = CONTOUR_KIND_LINEAR;
  776.         contour_order = 4;
  777.         contour_levels = 5;
  778.          levels_kind = LEVELS_AUTO;
  779.     } else if (almost_equals(c_token, "p$oints")) {
  780.         c_token++;
  781.         contour_pts = (int) real(const_express(&a));
  782.     } else if (almost_equals(c_token, "li$near")) {
  783.         c_token++;
  784.         contour_kind = CONTOUR_KIND_LINEAR;
  785.     } else if (almost_equals(c_token, "c$ubicspline")) {
  786.         c_token++;
  787.         contour_kind = CONTOUR_KIND_CUBIC_SPL;
  788.     } else if (almost_equals(c_token, "b$spline")) {
  789.         c_token++;
  790.         contour_kind = CONTOUR_KIND_BSPLINE;
  791.     } else if (almost_equals(c_token, "le$vels")) {
  792.         int i = 0;  /* local counter */
  793.         c_token++;
  794.         /*  RKC: I have modified the next two:
  795.          *   to use commas to separate list elements as in xtics
  796.          *   so that incremental lists start,incr[,end]as in "
  797.          */
  798.         if (almost_equals(c_token, "di$screte")) {
  799.         levels_kind = LEVELS_DISCRETE;
  800.         c_token++;
  801.         if(END_OF_COMMAND)
  802.             int_error("expecting discrete level", c_token);
  803.         else
  804.             levels_list[i++] = real(const_express(&a));
  805.  
  806.         while(!END_OF_COMMAND) {
  807.             if (!equals(c_token, ","))
  808.             int_error("expecting comma to separate discrete levels", c_token);
  809.             c_token++;
  810.             levels_list[i++] = real(const_express(&a));
  811.         }
  812.         contour_levels = i;
  813.         } else if (almost_equals(c_token, "in$cremental")) {
  814.         levels_kind = LEVELS_INCREMENTAL;
  815.         c_token++;
  816.         levels_list[i++] = real(const_express(&a));
  817.         if (!equals(c_token, ","))
  818.             int_error("expecting comma to separate start,incr levels", c_token);
  819.         c_token++;
  820.         if((levels_list[i++] = real(const_express(&a))) == 0)
  821.             int_error("increment cannot be 0", c_token);
  822.         if(!END_OF_COMMAND) {
  823.             if (!equals(c_token, ","))
  824.             int_error("expecting comma to separate incr,stop levels", c_token);
  825.             c_token++;
  826.             /* need to round up, since 10,10,50 is 5 levels, not four,
  827.              * but 10,10,49 is four
  828.              */
  829.             contour_levels = (int) ( (real(const_express(&a))-levels_list[0])/levels_list[1] + 1.0);
  830.         }
  831.         } else if (almost_equals(c_token, "au$to")) {
  832.         levels_kind = LEVELS_AUTO;
  833.         c_token++;
  834.         if(!END_OF_COMMAND)
  835.             contour_levels = (int) real(const_express(&a));
  836.         } else {
  837.         if(levels_kind == LEVELS_DISCRETE)
  838.             int_error("Levels type is discrete, ignoring new number of contour levels", c_token);
  839.         contour_levels = (int) real(const_express(&a));
  840.         }
  841.     } else if (almost_equals(c_token, "o$rder")) {
  842.         int order;
  843.         c_token++;
  844.         order = (int) real(const_express(&a));
  845.         if ( order < 2 || order > 10 )
  846.         int_error("bspline order must be in [2..10] range.", c_token);
  847.         contour_order = order;
  848.     } else
  849.         int_error("expecting 'linear', 'cubicspline', 'bspline', 'points', 'levels' or 'order'", c_token);
  850.     } else if (almost_equals(c_token,"da$ta")) {
  851.     c_token++;
  852.     if (!almost_equals(c_token,"s$tyle"))
  853.         int_error("expecting keyword 'style'",c_token);
  854.     data_style = get_style();
  855.     } else if (almost_equals(c_token,"dg$rid3d")) {
  856.     int i;
  857.     TBOOLEAN was_comma = TRUE;
  858.     int local_vals[3];
  859.     struct value a;
  860.  
  861.     local_vals[0] = dgrid3d_row_fineness;
  862.     local_vals[1] = dgrid3d_col_fineness;
  863.     local_vals[2] = dgrid3d_norm_value;
  864.     c_token++;
  865.     for (i = 0; i < 3 && !(END_OF_COMMAND);) {
  866.         if (equals(c_token,",")) {
  867.         if (was_comma) i++;
  868.             was_comma = TRUE;
  869.         c_token++;
  870.         } else {
  871.         if (!was_comma)
  872.             int_error("',' expected",c_token);
  873.         local_vals[i] = real(const_express(&a));
  874.         i++;
  875.         was_comma = FALSE;
  876.         }
  877.     }
  878.  
  879.     if (local_vals[0] < 2 || local_vals[0] > 1000)
  880.         int_error("Row size must be in [2:1000] range; size unchanged",
  881.               c_token);
  882.     if (local_vals[1] < 2 || local_vals[1] > 1000)
  883.         int_error("Col size must be in [2:1000] range; size unchanged",
  884.               c_token);
  885.     if (local_vals[2] < 1 || local_vals[2] > 100)
  886.         int_error("Norm must be in [1:100] range; norm unchanged", c_token);
  887.  
  888.     dgrid3d_row_fineness = local_vals[0];
  889.     dgrid3d_col_fineness = local_vals[1];
  890.     dgrid3d_norm_value = local_vals[2];
  891.     dgrid3d = TRUE;
  892.     } else if (almost_equals(c_token,"nodg$rid3d")) {
  893.     c_token++;
  894.     dgrid3d = FALSE;
  895.     } else if (almost_equals(c_token,"mis$sing")) {
  896.     c_token++;
  897.     if (END_OF_COMMAND) {
  898.         if (missing_val)
  899.         free(missing_val);
  900.         missing_val = NULL;
  901.     } else {
  902.         if (!isstring(c_token))
  903.         int_error("Expected missing-value string", c_token);
  904.         m_quote_capture(&missing_val, c_token, c_token);
  905.         c_token++;
  906.     }
  907.     } else if (almost_equals(c_token,"nomis$sing")) {
  908.     ++c_token;
  909.     if (missing_val)
  910.         free(missing_val);
  911.     missing_val = NULL;
  912.     } else if (almost_equals(c_token,"du$mmy")) {
  913.     c_token++;
  914.     if (END_OF_COMMAND)
  915.         int_error("expecting dummy variable name", c_token);
  916.     else {
  917.         if (!equals(c_token,","))
  918.         copy_str(dummy_var[0],c_token++, MAX_ID_LEN);
  919.         if (!END_OF_COMMAND && equals(c_token,",")) {
  920.         c_token++;
  921.         if (END_OF_COMMAND)
  922.             int_error("expecting second dummy variable name", c_token);
  923.         copy_str(dummy_var[1],c_token++, MAX_ID_LEN);
  924.         }
  925.     }
  926.     } else if (almost_equals(c_token,"fo$rmat")) {
  927.     TBOOLEAN setx = FALSE, sety = FALSE, setz = FALSE;
  928.     TBOOLEAN setx2 = FALSE, sety2 = FALSE;
  929.     c_token++;
  930.     if (equals(c_token,"x")) {
  931.         setx = TRUE;
  932.         c_token++;
  933.     } else if (equals(c_token,"y")) {
  934.         sety = TRUE;
  935.         c_token++;
  936.     } else if (equals(c_token,"x2")) {
  937.         setx2 = TRUE;
  938.         c_token++;
  939.     } else if (equals(c_token,"y2")) {
  940.         sety2 = TRUE;
  941.         c_token++;
  942.     } else if (equals(c_token,"z")) {
  943.         setz = TRUE;
  944.         c_token++;
  945.     } else if (equals(c_token,"xy") || equals(c_token,"yx")) {
  946.         setx = sety = TRUE;
  947.         c_token++;
  948.     } else if (isstring(c_token) || END_OF_COMMAND) {
  949.         /* Assume he wants all */
  950.         setx = sety = setz = setx2 = sety2 = TRUE;
  951.     }
  952.  
  953.     if (END_OF_COMMAND) {
  954.         if (setx) {
  955.         (void) strcpy(xformat,DEF_FORMAT);
  956.         format_is_numeric[FIRST_X_AXIS] = 1;
  957.         }
  958.         if (sety) {
  959.         (void) strcpy(yformat,DEF_FORMAT);
  960.         format_is_numeric[FIRST_Y_AXIS] = 1;
  961.         }
  962.         if (setz) {
  963.         (void) strcpy(zformat,DEF_FORMAT);
  964.         format_is_numeric[FIRST_Z_AXIS] = 1;
  965.         }
  966.         if (setx2) {
  967.         (void) strcpy(x2format,DEF_FORMAT);
  968.         format_is_numeric[SECOND_X_AXIS] = 1;
  969.         }
  970.         if (sety2) {
  971.         (void) strcpy(y2format,DEF_FORMAT);
  972.         format_is_numeric[SECOND_Y_AXIS] = 1;
  973.         }
  974.     } else {
  975.         if (!isstring(c_token))
  976.         int_error("expecting format string",c_token);
  977.         else {
  978.         if (setx) {
  979.             quote_str(xformat,c_token, MAX_ID_LEN);
  980.             format_is_numeric[FIRST_X_AXIS] = looks_like_numeric(xformat);
  981.         }
  982.         if (sety) {
  983.             quote_str(yformat,c_token, MAX_ID_LEN);
  984.             format_is_numeric[FIRST_Y_AXIS] = looks_like_numeric(yformat);
  985.         }
  986.         if (setz) {
  987.             quote_str(zformat,c_token, MAX_ID_LEN);
  988.             format_is_numeric[FIRST_Z_AXIS] =looks_like_numeric(zformat);
  989.         }
  990.         if (setx2) {
  991.             quote_str(x2format,c_token, MAX_ID_LEN);
  992.             format_is_numeric[SECOND_X_AXIS] = looks_like_numeric(x2format);
  993.         }
  994.         if (sety2) {
  995.             quote_str(y2format,c_token, MAX_ID_LEN);
  996.             format_is_numeric[SECOND_Y_AXIS] = looks_like_numeric(y2format);
  997.         }
  998.         c_token++;
  999.         }
  1000.     }
  1001.     } else if (almost_equals(c_token,"fu$nction")) {
  1002.     c_token++;
  1003.     if (!almost_equals(c_token,"s$tyle"))
  1004.         int_error("expecting keyword 'style'",c_token);
  1005.     func_style = get_style();
  1006.     } else if (almost_equals(c_token,"la$bel")) {
  1007.     c_token++;
  1008.     set_label();
  1009.     } else if (almost_equals(c_token,"nola$bel")) {
  1010.     c_token++;
  1011.     set_nolabel();
  1012.     } else if (almost_equals(c_token,"li$nestyle") || equals(c_token, "ls" )) {
  1013.     c_token++;
  1014.     set_linestyle();
  1015.     } else if (almost_equals(c_token,"noli$nestyle") || equals(c_token, "nols" )) {
  1016.     c_token++;
  1017.     set_nolinestyle();
  1018.     } else if (almost_equals(c_token,"lo$gscale")) {
  1019.     c_token++;
  1020.     if (END_OF_COMMAND) {
  1021.         is_log_x = is_log_y = is_log_z = is_log_x2 = is_log_y2 = TRUE;
  1022.         base_log_x = base_log_y = base_log_z = base_log_x2 = base_log_y2 = 10.0;
  1023.         log_base_log_x = log_base_log_y = log_base_log_z = log_base_log_x2 = log_base_log_y2 = M_LN10;
  1024.     } else {
  1025.         TBOOLEAN change_x = FALSE;
  1026.         TBOOLEAN change_y = FALSE;
  1027.         TBOOLEAN change_z = FALSE;
  1028.         TBOOLEAN change_x2 = FALSE;
  1029.         TBOOLEAN change_y2 = FALSE;
  1030.         double newbase = 10, log_newbase;
  1031.  
  1032.         if (equals(c_token, "x2"))
  1033.         change_x2 = TRUE;
  1034.         else if (equals(c_token, "y2"))
  1035.         change_y2 = TRUE;
  1036.         else { /* must not see x when x2, etc */
  1037.         if (chr_in_str(c_token, 'x'))
  1038.             change_x = TRUE;
  1039.         if (chr_in_str(c_token, 'y'))
  1040.             change_y = TRUE;
  1041.         if (chr_in_str(c_token, 'z'))
  1042.             change_z = TRUE;
  1043.         }
  1044.         c_token++;
  1045.         if (!END_OF_COMMAND) {
  1046.         struct value a;
  1047.         newbase = magnitude(const_express(&a));
  1048.         if (newbase < 1.1)
  1049.             int_error("log base must be >= 1.1; logscale unchanged",
  1050.         c_token);
  1051.         }
  1052.         log_newbase = log(newbase);
  1053.  
  1054.         if (change_x) {
  1055.         is_log_x = TRUE;
  1056.         base_log_x = newbase;
  1057.         log_base_log_x = log_newbase;
  1058.         }
  1059.         if (change_y) {
  1060.         is_log_y = TRUE;
  1061.         base_log_y = newbase;
  1062.         log_base_log_y = log_newbase;
  1063.         }
  1064.         if (change_z) {
  1065.         is_log_z = TRUE;
  1066.         base_log_z = newbase;
  1067.         log_base_log_z = log_newbase;
  1068.         }
  1069.         if (change_x2) {
  1070.         is_log_x2 = TRUE;
  1071.         base_log_x2 = newbase;
  1072.         log_base_log_x2 = log_newbase;
  1073.         }
  1074.         if (change_y2) {
  1075.         is_log_y2 = TRUE;
  1076.         base_log_y2 = newbase;
  1077.         log_base_log_y2 = log_newbase;
  1078.         }
  1079.     }
  1080.     } else if (almost_equals(c_token,"nolo$gscale")) {
  1081.     c_token++;
  1082.     if (END_OF_COMMAND) {
  1083.         is_log_x = is_log_y = is_log_z = is_log_x2 = is_log_y2 = FALSE;
  1084.     } else if (equals(c_token, "x2")) {
  1085.         is_log_x2 = FALSE; ++c_token;
  1086.     } else if (equals(c_token, "y2")) {
  1087.         is_log_y2 = FALSE; ++c_token;
  1088.     } else {
  1089.         if (chr_in_str(c_token, 'x')) {
  1090.         is_log_x = FALSE;
  1091.         base_log_x = 0.0;
  1092.         log_base_log_x = 0.0;
  1093.         }
  1094.         if (chr_in_str(c_token, 'y')) {
  1095.         is_log_y = FALSE;
  1096.         base_log_y = 0.0;
  1097.         log_base_log_y = 0.0;
  1098.         }
  1099.         if (chr_in_str(c_token, 'z')) {
  1100.         is_log_z = FALSE;
  1101.         base_log_z = 0.0;
  1102.         log_base_log_z = 0.0;
  1103.         }
  1104.         c_token++;
  1105.     }
  1106.     } else if (almost_equals(c_token,"of$fsets")) {
  1107.     c_token++;
  1108.     if (END_OF_COMMAND) {
  1109.         loff = roff = toff = boff = 0.0;  /* Reset offsets */
  1110.     } else {
  1111.         load_offsets (&loff,&roff,&toff,&boff);
  1112.     }
  1113.     } else if (almost_equals(c_token, "noof$fsets")) {
  1114.     loff = roff = toff = boff = 0.0;
  1115.     ++c_token;
  1116.     } else if(almost_equals(c_token,"b$ars")) {
  1117.     c_token++;
  1118.     if(END_OF_COMMAND) {
  1119.         bar_size = 1.0;
  1120.     } else if(almost_equals(c_token,"s$mall")) {
  1121.         bar_size = 0.0;
  1122.         ++c_token;
  1123.     } else if(almost_equals(c_token,"l$arge")) {
  1124.         bar_size = 1.0;
  1125.         ++c_token;
  1126.     } else {
  1127.         struct value a;
  1128.         bar_size = real(const_express(&a));
  1129.     }
  1130.     } else if (almost_equals(c_token, "nob$ars")) {
  1131.     ++c_token;
  1132.     bar_size = 0.0;
  1133.     } else if (almost_equals(c_token, "enco$ding")) {
  1134.     c_token++;
  1135.     if(END_OF_COMMAND) {
  1136.         encoding = ENCODING_DEFAULT;
  1137.     } else if (almost_equals(c_token,"def$ault")) {
  1138.         c_token++;
  1139.         encoding = ENCODING_DEFAULT;
  1140.     } else if (almost_equals(c_token,"iso$_8859_1")) {
  1141.         c_token++;
  1142.         encoding = ENCODING_ISO_8859_1;
  1143.     } else if (almost_equals(c_token,"cp4$37")) {
  1144.         c_token++;
  1145.         encoding = ENCODING_CP_437;
  1146.     } else if (almost_equals(c_token,"cp8$50")) {
  1147.         c_token++;
  1148.         encoding = ENCODING_CP_850;
  1149.     } else {
  1150.         int_error("expecting one of 'default', 'iso_8859_1', 'cp437' or 'cp850'", c_token);
  1151.     }
  1152.     } else
  1153.     return(FALSE);  /* no command match */
  1154.  
  1155.     return(TRUE);
  1156. }
  1157.  
  1158.  
  1159. /* return TRUE if a command match, FALSE if not */
  1160. static TBOOLEAN
  1161. set_two()
  1162. {
  1163.     if (almost_equals(c_token,"o$utput")) {
  1164.     if (multiplot) {
  1165.         int_error("you can't change the output in multiplot mode", c_token);
  1166.     }
  1167.  
  1168.     c_token++;
  1169.     if (END_OF_COMMAND) {    /* no file specified */
  1170.          term_set_output(NULL);
  1171.          if (outstr) {
  1172.         free(outstr);
  1173.         outstr = NULL; /* means STDOUT */
  1174.         }
  1175.     } else if (!isstring(c_token)) {
  1176.         int_error("expecting filename",c_token);
  1177.     } else {
  1178.         /* on int_error, we'd like to remember that this is allocated */
  1179.         static char *testfile = NULL;
  1180.         m_quote_capture(&testfile,c_token, c_token); /* reallocs store */
  1181.         /* Skip leading whitespace */
  1182.         while (isspace((int)*testfile))
  1183.         testfile++;
  1184.         ++c_token;
  1185.         term_set_output(testfile);
  1186.         /* if we get here then it worked, and outstr now = testfile */
  1187.         testfile = NULL;
  1188.     }
  1189.     } else if (almost_equals(c_token,"origin")) {
  1190.     struct value s;
  1191.     c_token++;
  1192.     if (END_OF_COMMAND) {
  1193.         xoffset = 0.0;
  1194.         yoffset = 0.0;
  1195.     } else {
  1196.         xoffset = real(const_express(&s));
  1197.         if (!equals(c_token,","))
  1198.         int_error("',' expected",c_token);
  1199.         c_token++;
  1200.         yoffset = real(const_express(&s));
  1201.     } 
  1202.     } else if (almost_equals(c_token,"tit$le")) {
  1203.     set_xyzlabel(&title);
  1204.     } else if (almost_equals(c_token,"xl$abel")) {
  1205.     set_xyzlabel(&xlabel);
  1206.     } else if (almost_equals(c_token,"yl$abel")) {
  1207.     set_xyzlabel(&ylabel);
  1208.     } else if (almost_equals(c_token,"zl$abel")) {
  1209.     set_xyzlabel(&zlabel);
  1210.     } else if (almost_equals(c_token,"x2l$abel")) {
  1211.     set_xyzlabel(&x2label);
  1212.     } else if (almost_equals(c_token,"y2l$abel")) {
  1213.     set_xyzlabel(&y2label);
  1214.     } else if (almost_equals(c_token,"keyt$itle")) {
  1215.     c_token++;
  1216.     if (END_OF_COMMAND) {    /* set to default */
  1217.         key_title[0] = NUL;
  1218.     } else {
  1219.         if (isstring(c_token)) {
  1220.         /* We have string specified - grab it. */
  1221.         quote_str(key_title,c_token, MAX_LINE_LEN);
  1222.         c_token++;
  1223.         }
  1224.         /* c_token++; */
  1225.     }
  1226.     } else if (almost_equals(c_token, "nokeyt$itle")) {
  1227.     ++c_token;
  1228.     *key_title = 0;
  1229.     } else if (almost_equals(c_token,"timef$mt")) {
  1230.     c_token++;
  1231.     if (END_OF_COMMAND) {    /* set to default */
  1232.         strcpy(timefmt,TIMEFMT);
  1233.     } else {
  1234.         if (isstring(c_token)) {
  1235.         /* We have string specified - grab it. */
  1236.         quote_str(timefmt,c_token, 25);
  1237.         }
  1238.         c_token++;
  1239.     }
  1240.     } else if (almost_equals(c_token,"loc$ale")) {
  1241.     c_token++;
  1242.     if (END_OF_COMMAND) {
  1243.         set_locale("C");
  1244.     } else if (isstring(c_token)) {
  1245.         char ss[MAX_ID_LEN+1];
  1246.         quote_str(ss,c_token,MAX_ID_LEN);
  1247.         set_locale(ss);
  1248.         ++c_token;
  1249.     } else {
  1250.         int_error("Expected string", c_token);
  1251.     }
  1252.     }
  1253.  
  1254. #define DO_ZEROAX(variable, string,neg) \
  1255. else if (almost_equals(c_token, string)) { \
  1256.    ++c_token; if (END_OF_COMMAND) variable.l_type = -1; \
  1257.    else { \
  1258.       struct value a; \
  1259.       int old_token = c_token;\
  1260.       LP_PARSE(variable,1,0,-1,0); \
  1261.       if (old_token == c_token) \
  1262.          variable.l_type = real(const_express(&a)) - 1; \
  1263.    }\
  1264. } else if (almost_equals(c_token, neg)) { \
  1265.    ++c_token; variable.l_type = -3; \
  1266. }
  1267.  
  1268.     DO_ZEROAX(xzeroaxis, "xzero$axis", "noxzero$axis")
  1269.     DO_ZEROAX(yzeroaxis, "yzero$axis", "noyzero$axis")
  1270.     DO_ZEROAX(x2zeroaxis, "x2zero$axis", "nox2zero$axis")
  1271.     DO_ZEROAX(y2zeroaxis, "y2zero$axis", "noy2zero$axis")
  1272.  
  1273.     else if (almost_equals(c_token,"zeroa$xis")) {
  1274.     c_token++;
  1275.     LP_PARSE(xzeroaxis,1,0,-1,0);
  1276.     memcpy(&yzeroaxis,&xzeroaxis,sizeof(struct lp_style_type));
  1277.     } else if (almost_equals(c_token,"nozero$axis")) {
  1278.     c_token++;
  1279.     xzeroaxis.l_type  = -3;
  1280.     yzeroaxis.l_type  = -3;
  1281.     x2zeroaxis.l_type = -3;
  1282.     y2zeroaxis.l_type = -3;
  1283.     } else if (almost_equals(c_token,"par$ametric")) {
  1284.     if (!parametric) {
  1285.         parametric = TRUE;
  1286.         if (!polar) { /* already done for polar */
  1287.         strcpy (dummy_var[0], "t");
  1288.         strcpy (dummy_var[1], "y");
  1289.         if (interactive)
  1290.              (void) fprintf(stderr,"\n\tdummy variable is t for curves, u/v for surfaces\n");
  1291.         }
  1292.     }
  1293.     c_token++;
  1294.     } else if (almost_equals(c_token,"nopar$ametric")) {
  1295.     if (parametric) {
  1296.         parametric = FALSE;
  1297.         if (!polar) { /* keep t for polar */
  1298.         strcpy (dummy_var[0], "x");
  1299.         strcpy (dummy_var[1], "y");
  1300.         if (interactive)
  1301.            (void) fprintf(stderr,"\n\tdummy variable is x for curves, x/y for surfaces\n");
  1302.         }
  1303.     }
  1304.     c_token++;
  1305.     } else if (almost_equals(c_token, "poi$ntsize")) {
  1306.     struct value a;
  1307.     c_token++;
  1308.     if (END_OF_COMMAND)
  1309.        pointsize = 1.0;
  1310.     else
  1311.         pointsize = real(const_express(&a));
  1312.     if(pointsize <= 0) pointsize = 1;
  1313.     } else if (almost_equals(c_token,"pol$ar")) {
  1314.     if (!polar) {
  1315.         if (!parametric) {
  1316.         if (interactive)
  1317.             (void) fprintf(stderr,"\n\tdummy variable is t for curves\n");
  1318.         strcpy (dummy_var[0], "t");
  1319.         }
  1320.         polar = TRUE;
  1321.         if (autoscale_t) {
  1322.         /* only if user has not set a range manually */
  1323.         tmin = 0.0;
  1324.         tmax = 2*Pi / ang2rad;  /* 360 if degrees, 2pi if radians */
  1325.         }
  1326.     }
  1327.     c_token++;
  1328.     } else if (almost_equals(c_token,"nopo$lar")) {
  1329.     if (polar) {
  1330.         polar = FALSE;
  1331.         if (parametric && autoscale_t) {
  1332.         /* only if user has not set an explicit range */
  1333.         tmin = -5.0;
  1334.         tmax = 5.0;
  1335.         }
  1336.         if (!parametric) {
  1337.         strcpy (dummy_var[0], "x");
  1338.         if (interactive)
  1339.             (void) fprintf(stderr,"\n\tdummy variable is x for curves\n");
  1340.         }
  1341.     }
  1342.     c_token++;
  1343.     } else if (almost_equals(c_token,"an$gles")) {
  1344.     c_token++;
  1345.     if (END_OF_COMMAND) {
  1346.         /* assuming same as defaults */
  1347.         angles_format = ANGLES_RADIANS;
  1348.         ang2rad = 1;
  1349.     } else if (almost_equals(c_token, "r$adians")) {
  1350.         angles_format = ANGLES_RADIANS;
  1351.         c_token++;
  1352.         ang2rad = 1;
  1353.     } else if (almost_equals(c_token, "d$egrees")) {
  1354.         angles_format = ANGLES_DEGREES;
  1355.         c_token++;
  1356.         ang2rad = DEG2RAD;
  1357.     } else
  1358.         int_error("expecting 'radians' or 'degrees'", c_token);
  1359.  
  1360.     if (polar && autoscale_t) {
  1361.         /* set trange if in polar mode and no explicit range */
  1362.         tmin = 0;
  1363.         tmax = 2*Pi/ang2rad;
  1364.     }
  1365.     }
  1366.  
  1367. #define GRID_MATCH(string, neg, mask) \
  1368. if (almost_equals(c_token, string)) { work_grid.l_type |= mask; ++c_token; } \
  1369. else if (almost_equals(c_token, neg)) { work_grid.l_type &= ~(mask); ++c_token; }
  1370.  
  1371.     else if (almost_equals(c_token,"g$rid")) {
  1372.     c_token++;
  1373.     if (END_OF_COMMAND && !work_grid.l_type)
  1374.         work_grid.l_type = GRID_X|GRID_Y;
  1375.     else
  1376.         while (!END_OF_COMMAND) {
  1377.         GRID_MATCH("x$tics", "nox$tics", GRID_X)
  1378.         else GRID_MATCH("y$tics", "noy$tics", GRID_Y)
  1379.         else GRID_MATCH("z$tics", "noz$tics", GRID_Z)
  1380.         else GRID_MATCH("x2$tics", "nox2$tics", GRID_X2)
  1381.         else GRID_MATCH("y2$tics", "noy2$tics", GRID_Y2)
  1382.         else GRID_MATCH("mx$tics", "nomx$tics", GRID_MX)
  1383.         else GRID_MATCH("my$tics", "nomy$tics", GRID_MY)
  1384.         else GRID_MATCH("mz$tics", "nomz$tics", GRID_MZ)
  1385.         else GRID_MATCH("mx2$tics", "nomx2$tics", GRID_MX2)
  1386.         else GRID_MATCH("my2$tics", "nomy2$tics", GRID_MY2)
  1387.         else if (almost_equals(c_token,"po$lar")) {
  1388.             if (!work_grid.l_type)
  1389.             work_grid.l_type = GRID_X;
  1390.             c_token++;
  1391.             if (END_OF_COMMAND) {
  1392.             polar_grid_angle = 30*DEG2RAD;
  1393.             } else {
  1394.             /* get radial interval */
  1395.             struct value a;
  1396.             polar_grid_angle = ang2rad*real(const_express(&a));
  1397.             }
  1398.         } else if (almost_equals(c_token,"nopo$lar")) {
  1399.             polar_grid_angle = 0; /* not polar grid */
  1400.             c_token++;
  1401.         } else
  1402.             break; /* might be a linetype */
  1403.         }
  1404.  
  1405.     if (!END_OF_COMMAND) {
  1406.         struct value a;
  1407.         int old_token = c_token;
  1408.  
  1409.         LP_PARSE(grid_lp,1,0,-1,1);
  1410.         if (c_token == old_token) { /* nothing parseable found... */
  1411.         grid_lp.l_type = real(const_express(&a)) - 1;
  1412.         }
  1413.             
  1414.         if (!work_grid.l_type)
  1415.         work_grid.l_type = GRID_X|GRID_Y;
  1416.         /* probably just  set grid <linetype> */
  1417.  
  1418.         if (END_OF_COMMAND) {
  1419.         memcpy(&mgrid_lp,&grid_lp,sizeof(struct lp_style_type));
  1420.         } else {
  1421.         if (equals(c_token,",")) 
  1422.             c_token++;
  1423.         old_token = c_token;
  1424.         LP_PARSE(mgrid_lp,1,0,-1,1);
  1425.         if (c_token == old_token) {
  1426.             mgrid_lp.l_type = real(const_express(&a)) -1;
  1427.         }
  1428.         }
  1429.  
  1430.         if (!work_grid.l_type)
  1431.         work_grid.l_type = GRID_X|GRID_Y;
  1432.         /* probably just  set grid <linetype> */
  1433.     }
  1434.  
  1435.     } else if (almost_equals(c_token,"nog$rid")) {
  1436.     work_grid.l_type = GRID_OFF;
  1437.     c_token++;
  1438.     } else if (almost_equals(c_token,"su$rface")) {
  1439.     draw_surface = TRUE;
  1440.     c_token++;
  1441.     } else if (almost_equals(c_token,"nosu$rface")) {
  1442.     draw_surface = FALSE;
  1443.     c_token++;
  1444.     } else if (almost_equals(c_token,"bor$der")) {
  1445.     struct value a;
  1446.     c_token++;
  1447.     if(END_OF_COMMAND){
  1448.         draw_border = 31;
  1449.     } else {
  1450.         draw_border = (int)real(const_express(&a));
  1451.     }
  1452.     /* HBB 980609: add linestyle handling for 'set border...' */
  1453.     /* For now, you have to give a border bitpattern to be able to specify a linestyle. Sorry for this,
  1454.      * but the gnuplot parser really is too messy for any other solution, currently */
  1455.     if(END_OF_COMMAND) {
  1456.         set_lp_properties(&border_lp, 0, -2, 0, 1.0, 1.0);
  1457.     } else {
  1458.         LP_PARSE(border_lp, 1, 0, -2, 0);
  1459.     }
  1460.     } else if (almost_equals(c_token,"k$ey")) {
  1461.     struct value a;
  1462.     c_token++;
  1463.     if (END_OF_COMMAND) {
  1464.         key = -1;
  1465.         key_vpos = TTOP;
  1466.         key_hpos = TRIGHT;
  1467.         key_just = JRIGHT;
  1468.         key_reverse = FALSE;
  1469.         set_lp_properties(&key_box,0,-3,0,1.0,1.0);
  1470.         key_swidth = 4;
  1471.         key_vert_factor = 1;
  1472.         key_width_fix = 0;
  1473.         key_title[0] = 0;
  1474.     } else {
  1475.         while (!END_OF_COMMAND) {
  1476.         if (almost_equals(c_token,"t$op")) {
  1477.             key_vpos = TTOP;
  1478.             key = -1;
  1479.         } else if (almost_equals(c_token,"b$ottom")) {
  1480.             key_vpos = TBOTTOM;
  1481.             key = -1;
  1482.         } else if (almost_equals(c_token,"l$eft")) {
  1483.             key_hpos = TLEFT;
  1484.             /* key_just = TRIGHT; */
  1485.             key = -1;
  1486.         } else if (almost_equals(c_token,"r$ight")) {
  1487.             key_hpos = TRIGHT;
  1488.             key = -1;
  1489.         } else if (almost_equals(c_token,"u$nder") ||
  1490.                almost_equals(c_token,"be$low")) {
  1491.             key_vpos = TUNDER;
  1492.             if (key_hpos == TOUT)
  1493.             key_hpos--;
  1494.             key = -1;
  1495.         } else if (almost_equals(c_token,"o$utside")) {
  1496.             key_hpos = TOUT;
  1497.             if (key_vpos == TUNDER)
  1498.             key_vpos--;
  1499.             key = -1;
  1500.         } else if (almost_equals(c_token,"L$eft")) {
  1501.             /* key_hpos = TLEFT; */
  1502.             key_just = JLEFT;
  1503.             /* key = -1; */
  1504.         } else if (almost_equals(c_token,"R$ight")) {
  1505.             /* key_hpos = TLEFT; */
  1506.             key_just = JRIGHT;
  1507.             /* key = -1; */
  1508.         } else if (almost_equals(c_token,"rev$erse")) {
  1509.             key_reverse = TRUE;
  1510.         } else if (almost_equals(c_token,"norev$erse")) {
  1511.             key_reverse = FALSE;
  1512.         } else if (equals(c_token,"box")) {
  1513.             ++c_token;
  1514.             if (END_OF_COMMAND)
  1515.             key_box.l_type = -2;
  1516.             else {
  1517.             int old_token = c_token;
  1518.     
  1519.             LP_PARSE(key_box,1,0,-2,0);
  1520.             if (old_token == c_token) {
  1521.                 key_box.l_type = real(const_express(&a)) -1;
  1522.             }
  1523.             }        
  1524.             --c_token;  /* is incremented after loop */
  1525.         } else if (almost_equals(c_token,"nob$ox")) {
  1526.             key_box.l_type = -3;
  1527.         } else if (almost_equals(c_token, "sa$mplen")) {
  1528.             ++c_token;
  1529.             key_swidth = real(const_express(&a));
  1530.             --c_token; /* it is incremented after loop */
  1531.         } else if (almost_equals(c_token, "sp$acing")) {
  1532.             ++c_token;
  1533.             key_vert_factor = real(const_express(&a));
  1534.             if (key_vert_factor < 0.0)
  1535.             key_vert_factor = 0.0;
  1536.             --c_token; /* it is incremented after loop */
  1537.         } else if (almost_equals(c_token, "w$idth")) {
  1538.             ++c_token;
  1539.             key_width_fix = real(const_express(&a));
  1540.             --c_token; /* it is incremented after loop */
  1541.         } else if (almost_equals(c_token,"ti$tle")) {
  1542.             if (isstring(c_token+1)) {
  1543.             /* We have string specified - grab it. */
  1544.             quote_str(key_title,++c_token, MAX_LINE_LEN);
  1545.             }
  1546.             else
  1547.             key_title[0] = 0;
  1548.         } else {
  1549.             get_position(&key_user_pos);
  1550.             key = 1;
  1551.             --c_token;  /* will be incremented again soon */
  1552.         } 
  1553.         c_token++;
  1554.          } 
  1555.     }
  1556.     } else if (almost_equals(c_token,"nok$ey")) {
  1557.     key = 0;
  1558.     c_token++;
  1559.     } else if (almost_equals(c_token,"tic$s")) {
  1560.     tic_in = TRUE;
  1561.     c_token++;
  1562.     if (almost_equals(c_token,"i$n")) {
  1563.         tic_in = TRUE;
  1564.         c_token++;
  1565.     } else if (almost_equals(c_token,"o$ut")) {
  1566.         tic_in = FALSE;
  1567.         c_token++;
  1568.     }
  1569.     } else if (almost_equals(c_token,"xda$ta")) {
  1570.     c_token++;
  1571.     if(END_OF_COMMAND) {
  1572.         datatype[FIRST_X_AXIS] = FALSE;
  1573.         /* eh ? - t and u have nothing to do with x */
  1574.         datatype[T_AXIS] = FALSE;
  1575.         datatype[U_AXIS] = FALSE;
  1576.     } else {
  1577.         if (almost_equals(c_token,"t$ime")) {
  1578.         datatype[FIRST_X_AXIS] = TIME;
  1579.         datatype[T_AXIS] = TIME;
  1580.         datatype[U_AXIS] = TIME;
  1581.         } else {
  1582.         datatype[FIRST_X_AXIS] = FALSE;
  1583.         datatype[T_AXIS] = FALSE;
  1584.         datatype[U_AXIS] = FALSE;
  1585.         }
  1586.         c_token++;
  1587.     }
  1588.     } else if (almost_equals(c_token,"yda$ta")) {
  1589.     c_token++;
  1590.     if(END_OF_COMMAND) {
  1591.         datatype[FIRST_Y_AXIS] = FALSE;
  1592.         datatype[V_AXIS] = FALSE;
  1593.     } else {
  1594.         if (almost_equals(c_token,"t$ime")) {
  1595.         datatype[FIRST_Y_AXIS] = TIME;
  1596.         datatype[V_AXIS] = TIME;
  1597.         } else {
  1598.         datatype[FIRST_Y_AXIS] = FALSE;
  1599.         datatype[V_AXIS] = FALSE;
  1600.         }
  1601.         c_token++;
  1602.     }
  1603.     } else if (almost_equals(c_token,"zda$ta")) {
  1604.     c_token++;
  1605.     if(END_OF_COMMAND) {
  1606.         datatype[FIRST_Z_AXIS] = FALSE;
  1607.     } else {
  1608.         if (almost_equals(c_token,"t$ime")) {
  1609.         datatype[FIRST_Z_AXIS] = TIME;
  1610.         } else {
  1611.         datatype[FIRST_Z_AXIS] = FALSE;
  1612.         }
  1613.         c_token++;
  1614.     }
  1615.     } else if (almost_equals(c_token,"x2da$ta")) {
  1616.     c_token++;
  1617.     if(END_OF_COMMAND) {
  1618.         datatype[SECOND_X_AXIS] = FALSE;
  1619.     } else {
  1620.         if (almost_equals(c_token,"t$ime")) {
  1621.         datatype[SECOND_X_AXIS] = TIME;
  1622.         } else {
  1623.         datatype[SECOND_X_AXIS] = FALSE;
  1624.         }
  1625.         c_token++;
  1626.     }
  1627.     } else if (almost_equals(c_token,"y2da$ta")) {
  1628.     c_token++;
  1629.     if(END_OF_COMMAND) {
  1630.         datatype[SECOND_Y_AXIS] = FALSE;
  1631.     } else {
  1632.         if (almost_equals(c_token,"t$ime")) {
  1633.         datatype[SECOND_Y_AXIS] = TIME;
  1634.         } else {
  1635.         datatype[SECOND_Y_AXIS] = FALSE;
  1636.         }
  1637.         c_token++;
  1638.     }
  1639.     }
  1640.  
  1641. /* to save duplicating code for x/y/z/x2/y2, make a macro
  1642.  * (should perhaps be a function ?)
  1643.  * unfortunately, string concatenation is not supported on all compilers,
  1644.  * so we have to explicitly include both 'on' and 'no' strings in
  1645.  * the args
  1646.  */
  1647.  
  1648. /* change to a function: lph 25.09.1998 */
  1649.  
  1650. #define PROCESS_TIC_COMMANDS  set_tic_prop
  1651.  
  1652.     else if 
  1653.     (PROCESS_TIC_COMMANDS(&x2tics, &mx2tics, &mx2tfreq, &x2ticdef, 
  1654.      SECOND_X_AXIS, &rotate_x2tics, "x2") );
  1655.     else if 
  1656.     (PROCESS_TIC_COMMANDS(&y2tics, &my2tics, &my2tfreq, &y2ticdef,
  1657.      SECOND_Y_AXIS, &rotate_y2tics, "y2") );
  1658.     else if
  1659.     (PROCESS_TIC_COMMANDS(&xtics,   &mxtics, &mxtfreq,  &xticdef,
  1660.      FIRST_X_AXIS, &rotate_xtics, "x") );
  1661.     else if
  1662.     (PROCESS_TIC_COMMANDS(&ytics,   &mytics, &mytfreq,  &yticdef, 
  1663.      FIRST_Y_AXIS, &rotate_ytics, "y") );
  1664.     else if 
  1665.     (PROCESS_TIC_COMMANDS(&ztics,   &mztics, &mztfreq,  &zticdef,
  1666.      FIRST_Z_AXIS, &rotate_ztics, "z") );
  1667.  
  1668.     else if (almost_equals(c_token,"ticsl$evel")) {
  1669.     double tlvl;
  1670.     struct value a;
  1671.  
  1672.     c_token++;
  1673.     /* is datatype 'time' relevant here ? */
  1674.     tlvl = real(const_express(&a));
  1675.     ticslevel = tlvl;
  1676.     }
  1677.  
  1678. #define PROCESS_MARGIN(variable, string) \
  1679. else if (almost_equals(c_token,string)) {\
  1680.  ++c_token; if (END_OF_COMMAND) variable = -1;\
  1681.  else { struct value a; variable = real(const_express(&a)); } \
  1682. }
  1683.  
  1684.     PROCESS_MARGIN(lmargin, "lmar$gin")
  1685.     PROCESS_MARGIN(bmargin, "bmar$gin")
  1686.     PROCESS_MARGIN(rmargin, "rmar$gin")
  1687.     PROCESS_MARGIN(tmargin, "tmar$gin")
  1688.  
  1689.     else
  1690.     return(FALSE);    /* no command match */
  1691.  
  1692.     return(TRUE);
  1693. }
  1694.  
  1695.  
  1696.  
  1697. /* return TRUE if a command match, FALSE if not */
  1698. static TBOOLEAN
  1699. set_three()
  1700. {
  1701.     if (almost_equals(c_token,"sa$mples")) {
  1702.     register int tsamp1, tsamp2;
  1703.     struct value a;
  1704.  
  1705.     c_token++;
  1706.     tsamp1 = (int)magnitude(const_express(&a));
  1707.     tsamp2 = tsamp1;
  1708.     if (!END_OF_COMMAND) {
  1709.         if (!equals(c_token,","))
  1710.         int_error("',' expected",c_token);
  1711.         c_token++;
  1712.         tsamp2 = (int)magnitude(const_express(&a));
  1713.     }
  1714.     if (tsamp1 < 2 || tsamp2 < 2)
  1715.         int_error("sampling rate must be > 1; sampling unchanged",c_token);
  1716.     else {
  1717.         register struct surface_points *f_3dp = first_3dplot;
  1718.  
  1719.         first_3dplot = NULL;
  1720.         sp_free(f_3dp);
  1721.  
  1722.         samples = tsamp1;
  1723.         samples_1 = tsamp1;
  1724.         samples_2 = tsamp2;
  1725.     }
  1726.     } else if (almost_equals(c_token,"isosa$mples")) {
  1727.     register int tsamp1, tsamp2;
  1728.     struct value a;
  1729.  
  1730.     c_token++;
  1731.     tsamp1 = (int)magnitude(const_express(&a));
  1732.     tsamp2 = tsamp1;
  1733.     if (!END_OF_COMMAND) {
  1734.         if (!equals(c_token,","))
  1735.         int_error("',' expected",c_token);
  1736.         c_token++;
  1737.         tsamp2 = (int)magnitude(const_express(&a));
  1738.     }
  1739.     if (tsamp1 < 2 || tsamp2 < 2)
  1740.         int_error("sampling rate must be > 1; sampling unchanged",c_token);
  1741.     else {
  1742.         register struct curve_points *f_p = first_plot;
  1743.         register struct surface_points *f_3dp = first_3dplot;
  1744.  
  1745.         first_plot = NULL;
  1746.         first_3dplot = NULL;
  1747.         cp_free(f_p);
  1748.         sp_free(f_3dp);
  1749.  
  1750.         iso_samples_1 = tsamp1;
  1751.         iso_samples_2 = tsamp2;
  1752.     }
  1753.     } else if (almost_equals(c_token,"si$ze")) {
  1754.     struct value s;
  1755.     c_token++;
  1756.     if (END_OF_COMMAND) {
  1757.         xsize = 1.0;
  1758.         ysize = 1.0;
  1759.     } else {
  1760.         if (almost_equals(c_token, "sq$uare")) {
  1761.         aspect_ratio = 1.0;
  1762.         ++c_token;
  1763.         } else if (almost_equals(c_token,"ra$tio")) {
  1764.         ++c_token;
  1765.         aspect_ratio = real(const_express(&s));
  1766.         } else if (almost_equals(c_token, "nora$tio") || almost_equals(c_token, "nosq$uare")) {
  1767.         aspect_ratio = 0.0;
  1768.         ++c_token;
  1769.         }
  1770.                     
  1771.         if (!END_OF_COMMAND) {
  1772.         xsize = real(const_express(&s));
  1773.         if (equals(c_token,",")) {
  1774.             c_token++;
  1775.             ysize = real(const_express(&s));
  1776.         } else {
  1777.             ysize = xsize;
  1778.         }
  1779.         }
  1780.     }
  1781.     } else if (almost_equals(c_token,"ticsc$ale")) {
  1782.     struct value tscl;
  1783.     c_token++;
  1784.     if (END_OF_COMMAND) {
  1785.         ticscale = 1.0;
  1786.         miniticscale = 0.5;
  1787.     } else {
  1788.         ticscale = real(const_express(&tscl));
  1789.         if (END_OF_COMMAND) {
  1790.         miniticscale = ticscale*0.5;
  1791.         } else {
  1792.         miniticscale = real(const_express(&tscl));
  1793.         }
  1794.     }
  1795.     } else if (almost_equals(c_token,"t$erminal")) {
  1796.     if (multiplot) {
  1797.          int_error("You can't change the terminal in multiplot mode", c_token);
  1798.     }
  1799.  
  1800.     c_token++;
  1801.     if (END_OF_COMMAND) {
  1802.         list_terms();
  1803.         screen_ok = FALSE;
  1804.     } else {
  1805.         term_reset();
  1806.         term = 0; /* in case set_term() fails */
  1807.         term = set_term(c_token);
  1808.         c_token++;
  1809.  
  1810.         /* get optional mode parameters
  1811.          * not all drivers reset the option string before
  1812.          * strcat-ing to it, so we reset it for them
  1813.          */
  1814.         *term_options = 0;
  1815.         if (term)
  1816.         (*term->options)();
  1817.         if (interactive && *term_options)
  1818.         fprintf(stderr,"Options are '%s'\n",term_options);
  1819.     }
  1820.     } else if (almost_equals(c_token,"tim$estamp")) {
  1821.     c_token++;
  1822.     if (END_OF_COMMAND || !isstring(c_token))
  1823.         strcpy(timelabel.text, DEFAULT_TIMESTAMP_FORMAT);
  1824.  
  1825.     if (!END_OF_COMMAND) {
  1826.         struct value a;
  1827.  
  1828.         if (isstring(c_token)) {
  1829.         /* we have a format string */
  1830.         quote_str(timelabel.text, c_token, MAX_LINE_LEN);
  1831.         ++c_token;
  1832.         } else {
  1833.         strcpy(timelabel.text, DEFAULT_TIMESTAMP_FORMAT);
  1834.         }
  1835.         if (almost_equals(c_token,"t$op")) {
  1836.         timelabel_bottom = FALSE;
  1837.             ++c_token;
  1838.         } else if (almost_equals(c_token, "b$ottom")) {
  1839.         timelabel_bottom = TRUE;
  1840.             ++c_token;
  1841.         }
  1842.         if (almost_equals(c_token,"r$otate")) {
  1843.         timelabel_rotate = TRUE;
  1844.             ++c_token;
  1845.         } else if (almost_equals(c_token, "n$orotate")) {
  1846.         timelabel_rotate = FALSE;
  1847.             ++c_token;
  1848.         }
  1849.         /* We have x,y offsets specified */
  1850.         if (!END_OF_COMMAND && !equals(c_token,","))
  1851.         timelabel.xoffset = real(const_express(&a));
  1852.         if (!END_OF_COMMAND && equals(c_token,",")) {
  1853.         c_token++;
  1854.         timelabel.yoffset = real(const_express(&a));
  1855.         }
  1856.         if (!END_OF_COMMAND && isstring(c_token)) {
  1857.         quote_str(timelabel.font, c_token, MAX_LINE_LEN);
  1858.         ++c_token;
  1859.         } else {
  1860.         *timelabel.font = 0;
  1861.         }
  1862.     }
  1863.     } else if (almost_equals(c_token,"not$imestamp")) {
  1864.     *timelabel.text = 0;
  1865.     c_token++;
  1866.     } else if (almost_equals(c_token,"vi$ew")) {
  1867.     int i;
  1868.     TBOOLEAN was_comma = TRUE;
  1869.     double local_vals[4];
  1870.     struct value a;
  1871.  
  1872.     local_vals[0] = surface_rot_x;
  1873.     local_vals[1] = surface_rot_z;
  1874.     local_vals[2] = surface_scale;
  1875.     local_vals[3] = surface_zscale;
  1876.     c_token++;
  1877.     for (i = 0; i < 4 && !(END_OF_COMMAND);) {
  1878.         if (equals(c_token,",")) {
  1879.         if (was_comma) i++;
  1880.             was_comma = TRUE;
  1881.         c_token++;
  1882.         } else {
  1883.         if (!was_comma)
  1884.             int_error("',' expected",c_token);
  1885.         local_vals[i] = real(const_express(&a));
  1886.         i++;
  1887.         was_comma = FALSE;
  1888.         }
  1889.     }
  1890.  
  1891.     if (local_vals[0] < 0 || local_vals[0] > 180)
  1892.         int_error("rot_x must be in [0:180] degrees range; view unchanged", c_token);
  1893.     if (local_vals[1] < 0 || local_vals[1] > 360)
  1894.         int_error("rot_z must be in [0:360] degrees range; view unchanged", c_token);
  1895.     if (local_vals[2] < 1e-6)
  1896.         int_error("scale must be > 0; view unchanged", c_token);
  1897.     if (local_vals[3] < 1e-6)
  1898.         int_error("zscale must be > 0; view unchanged", c_token);
  1899.  
  1900.     surface_rot_x = local_vals[0];
  1901.     surface_rot_z = local_vals[1];
  1902.     surface_scale = local_vals[2];
  1903.     surface_zscale = local_vals[3];
  1904.     }
  1905.  
  1906. /* to save replicated code, define a macro */
  1907. #define PROCESS_RANGE(AXIS,STRING, MIN, MAX, AUTO) \
  1908. else if (almost_equals(c_token, STRING)) { \
  1909.  if (!equals(++c_token,"[")) int_error("expecting '['",c_token); \
  1910.  c_token++; \
  1911.  AUTO = load_range(AXIS,&MIN,&MAX,AUTO); \
  1912.  if (!equals(c_token,"]")) int_error("expecting ']'",c_token); \
  1913.  c_token++; \
  1914.  if (almost_equals(c_token, "rev$erse")) { \
  1915.    ++c_token; range_flags[AXIS] |= RANGE_REVERSE;\
  1916.  } else if (almost_equals(c_token, "norev$erse")) { \
  1917.    ++c_token; range_flags[AXIS] &= ~RANGE_REVERSE;\
  1918.  } if (almost_equals(c_token, "wr$iteback")) { \
  1919.    ++c_token; range_flags[AXIS] |= RANGE_WRITEBACK;\
  1920.  } else if (almost_equals(c_token, "nowri$teback")) { \
  1921.    ++c_token; range_flags[AXIS] &= ~RANGE_WRITEBACK;\
  1922. }}
  1923.  
  1924.     PROCESS_RANGE(R_AXIS, "rr$ange", rmin, rmax, autoscale_r)
  1925.     PROCESS_RANGE(T_AXIS, "tr$ange", tmin, tmax, autoscale_t)
  1926.     PROCESS_RANGE(U_AXIS, "ur$ange", umin, umax, autoscale_u)
  1927.     PROCESS_RANGE(V_AXIS, "vr$ange", vmin, vmax, autoscale_v)
  1928.     PROCESS_RANGE(FIRST_X_AXIS, "xr$ange", xmin, xmax, autoscale_x)
  1929.     PROCESS_RANGE(FIRST_Y_AXIS, "yr$ange", ymin, ymax, autoscale_y)
  1930.     PROCESS_RANGE(FIRST_Z_AXIS, "zr$ange", zmin, zmax, autoscale_z)
  1931.     PROCESS_RANGE(SECOND_X_AXIS, "x2r$ange", x2min, x2max, autoscale_x2)
  1932.     PROCESS_RANGE(SECOND_Y_AXIS, "y2r$ange", y2min, y2max, autoscale_y2)
  1933.  
  1934.     else if (almost_equals(c_token,"z$ero")) {
  1935.     struct value a;
  1936.     c_token++;
  1937.     zero = magnitude(const_express(&a));
  1938.     } else if (almost_equals(c_token,"multi$plot")) {
  1939.     term_start_multiplot();
  1940.     c_token++;
  1941.     } else if (almost_equals(c_token,"nomulti$plot")) {
  1942.     term_end_multiplot();
  1943.     c_token++;
  1944.     } else
  1945.     return(FALSE);    /* no command match */
  1946.  
  1947.     return(TRUE);
  1948. }
  1949.  
  1950.  
  1951. /*********** Support functions for set_command ***********/
  1952.  
  1953. /*
  1954.  * The set.c PROCESS_TIC_PROP macro has the following characteristics:
  1955.  *   (a) options must in the correct order
  1956.  *   (b) 'set xtics' (no option) resets only the interval (FREQ)
  1957.  *       {it will also negate NO_TICS, see (d)} 
  1958.  *   (c) changing any property also resets the interval to automatic
  1959.  *   (d) set no[xy]tics; set [xy]tics changes border to nomirror, rather 
  1960.  *       than to the default, mirror.
  1961.  *   (e) effect of 'set no[]tics; set []tics border ...' is compiler
  1962.  *       dependent;  if '!(TICS)' is evaluated first, 'border' is an 
  1963.  *       undefined variable :-(
  1964.  *
  1965.  * This function replaces the macro, and introduces a new option
  1966.  * 'au$tofreq' to give somewhat different behaviour:
  1967.  *   (a) no change
  1968.  *   (b) 'set xtics' (no option) only affects NO_TICS;  'autofreq' resets 
  1969.  *       the interval calulation to automatic
  1970.  *   (c) the interval mode is not affected by changing some other option
  1971.  *   (d) if NO_TICS, set []tics will restore defaults (borders, mirror
  1972.  *       where appropriate)
  1973.  *   (e) if (NO_TICS), border option is processed.
  1974.  *
  1975.  *  A 'default' option could easily be added to reset all options to
  1976.  *  the initial values - mostly book-keeping.
  1977.  *
  1978.  *  To retain tic properties after setting no[]tics may also be
  1979.  *  straightforward (save value as negative), but requires changes
  1980.  *  in other code ( e.g. for  'if (xtics)', use 'if (xtics > 0)'
  1981.  */
  1982.  
  1983. static int set_tic_prop(TICS, MTICS, FREQ, tdef, AXIS, ROTATE, tic_side)
  1984. /*    generates PROCESS_TIC_PROP strings from tic_side, e.g. "x2" 
  1985.    STRING, NOSTRING, MONTH, NOMONTH, DAY, NODAY, MINISTRING, NOMINI
  1986.    "nox2t$ics"     "nox2m$tics"  "nox2d$tics"    "nomx2t$ics" 
  1987.  */
  1988.  
  1989. int *TICS, *MTICS, AXIS;
  1990. double *FREQ;
  1991. struct ticdef *tdef;
  1992. TBOOLEAN *ROTATE;
  1993. char *tic_side;
  1994.  
  1995.  
  1996. {
  1997.     int match = 0;        /* flag, set by matching a tic command */
  1998.     char nocmd[12];        /* fill w/ "no"+'tic_side'+suffix */
  1999.     char *cmdptr, *sfxptr;
  2000.  
  2001.     (void) strcpy(nocmd, "no");
  2002.     cmdptr = &nocmd[2];
  2003.     (void) strcpy(cmdptr, tic_side);
  2004.     sfxptr = &nocmd[strlen(nocmd)];
  2005.     (void) strcpy(sfxptr, "t$ics");    /* STRING */
  2006.  
  2007.     if (almost_equals(c_token, cmdptr)) {
  2008.     match = 1;
  2009.     if (almost_equals(++c_token, "ax$is")) {
  2010.         *TICS &= ~TICS_ON_BORDER;
  2011.         *TICS |= TICS_ON_AXIS;
  2012.         ++c_token;
  2013.     }
  2014.     /* if tics are off, reset to default (border) */
  2015.     if (*TICS == NO_TICS) {
  2016.         *TICS = TICS_ON_BORDER;
  2017.         if (!strcmp(tic_side, "x") || !strcmp(tic_side, "y")) {
  2018.         *TICS |= TICS_MIRROR;
  2019.         }
  2020.     }
  2021.     if (almost_equals(c_token, "bo$rder")) {
  2022.         *TICS &= ~TICS_ON_AXIS;
  2023.         *TICS |= TICS_ON_BORDER;
  2024.         ++c_token;
  2025.     }
  2026.     if (almost_equals(c_token, "mi$rror")) {
  2027.         *TICS |= TICS_MIRROR;
  2028.         ++c_token;
  2029.     } else if (almost_equals(c_token, "nomi$rror")) {
  2030.         *TICS &= ~TICS_MIRROR;
  2031.         ++c_token;
  2032.     }
  2033.     if (almost_equals(c_token, "ro$tate")) {
  2034.         *ROTATE = TRUE;
  2035.         ++c_token;
  2036.     } else if (almost_equals(c_token, "noro$tate")) {
  2037.         *ROTATE = FALSE;
  2038.         ++c_token;
  2039.     }
  2040.     if (almost_equals(c_token, "au$tofreq")) {    /* auto tic interval */
  2041.         ++c_token;
  2042.         if (tdef->type == TIC_USER) {
  2043.         free_marklist(tdef->def.user);
  2044.         tdef->def.user = NULL;
  2045.         }
  2046.         tdef->type = TIC_COMPUTED;
  2047.     }
  2048.     /* user spec. is last */ 
  2049.     else if (!END_OF_COMMAND) {
  2050.         load_tics(AXIS, tdef);
  2051.     }
  2052.     }
  2053.     if (almost_equals(c_token, nocmd)) {    /* NOSTRING */
  2054.     *TICS = NO_TICS;
  2055.     c_token++;
  2056.     match = 1;
  2057.     }
  2058. /* other options */
  2059.  
  2060.     (void) strcpy(sfxptr, "m$tics");    /* MONTH */
  2061.     if (almost_equals(c_token, cmdptr)) {
  2062.     if (tdef->type == TIC_USER) {
  2063.         free_marklist(tdef->def.user);
  2064.         tdef->def.user = NULL;
  2065.     }
  2066.     tdef->type = TIC_MONTH;
  2067.     ++c_token;
  2068.     match = 1;
  2069.     }
  2070.     if (almost_equals(c_token, nocmd)) {    /* NOMONTH */
  2071.     tdef->type = TIC_COMPUTED;
  2072.     ++c_token;
  2073.     match = 1;
  2074.     }
  2075.     (void) strcpy(sfxptr, "d$tics");    /* DAYS */
  2076.     if (almost_equals(c_token, cmdptr)) {
  2077.     match = 1;
  2078.     if (tdef->type == TIC_USER) {
  2079.         free_marklist(tdef->def.user);
  2080.         tdef->def.user = NULL;
  2081.     }
  2082.     tdef->type = TIC_DAY;
  2083.     ++c_token;
  2084.     }
  2085.     if (almost_equals(c_token, nocmd)) {    /* NODAYS */
  2086.     tdef->type = TIC_COMPUTED;
  2087.     ++c_token;
  2088.     match = 1;
  2089.     }
  2090.     *cmdptr = 'm';
  2091.     (void) strcpy(cmdptr + 1, tic_side);
  2092.     (void) strcat(cmdptr, "t$ics");    /* MINISTRING */
  2093.  
  2094.     if (almost_equals(c_token, cmdptr)) {
  2095.     struct value freq;
  2096.     c_token++;
  2097.     match = 1;
  2098.     if (END_OF_COMMAND) {
  2099.         *MTICS = MINI_AUTO;
  2100.     } else if (almost_equals(c_token, "def$ault")) {
  2101.         *MTICS = MINI_DEFAULT;
  2102.         ++c_token;
  2103.     } else {
  2104.         *FREQ = real(const_express(&freq));
  2105.         *FREQ = floor(*FREQ);
  2106.         *MTICS = MINI_USER;
  2107.     }
  2108.     }
  2109.     if (almost_equals(c_token, nocmd)) {    /* NOMINI */
  2110.     *MTICS = FALSE;
  2111.     c_token++;
  2112.     match = 1;
  2113.     }
  2114.     return (match);
  2115. }
  2116.  
  2117.  
  2118. /* process a 'set {x/y/z}label command */
  2119. /* set {x/y/z}label {label_text} {x}{,y} */
  2120. static void set_xyzlabel(label)
  2121. label_struct *label;
  2122. {
  2123.     c_token++;
  2124.     if (END_OF_COMMAND) {    /* no label specified */
  2125.     *label->text = '\0';
  2126.     return;
  2127.     }
  2128.     if (isstring(c_token)) {
  2129.     /* We have string specified - grab it. */
  2130.     quote_str(label->text, c_token, MAX_LINE_LEN);
  2131.     c_token++;
  2132.     }
  2133.     if (END_OF_COMMAND)
  2134.     return;
  2135.  
  2136.     if (!almost_equals(c_token, "font") && !isstring(c_token)) {
  2137.     /* We have x,y offsets specified */
  2138.     struct value a;
  2139.     if (!equals(c_token, ","))
  2140.         label->xoffset = real(const_express(&a));
  2141.  
  2142.     if (END_OF_COMMAND)
  2143.         return;
  2144.  
  2145.     if (equals(c_token, ",")) {
  2146.         c_token++;
  2147.         label->yoffset = real(const_express(&a));
  2148.     }
  2149.     }
  2150.     if (END_OF_COMMAND)
  2151.     return;
  2152.  
  2153.     /* optional keyword 'font' can go here */
  2154.  
  2155.     if (almost_equals(c_token, "f$ont"))
  2156.     ++c_token;        /* skip it */
  2157.  
  2158.     if (!isstring(c_token))
  2159.     int_error("Expected font", c_token);
  2160.  
  2161.     quote_str(label->font, c_token, MAX_LINE_LEN);
  2162.     c_token++;
  2163. }
  2164.  
  2165. /* process a 'set label' command */
  2166. /* set label {tag} {label_text} {at x,y} {pos} {font name,size} */
  2167. /* Entry font added by DJL */
  2168. static void set_label()
  2169. {
  2170.     struct value a;
  2171.     struct text_label *this_label = NULL;
  2172.     struct text_label *new_label = NULL;
  2173.     struct text_label *prev_label = NULL;
  2174.     struct position pos;
  2175.     char text[MAX_LINE_LEN + 1], font[MAX_LINE_LEN + 1];
  2176.     enum JUSTIFY just = LEFT;
  2177.     int rotate = 0;
  2178.     int tag;
  2179.     TBOOLEAN set_text, set_position, set_just = FALSE, set_rot = FALSE,
  2180.      set_font;
  2181.  
  2182.     /* get tag */
  2183.     if (!END_OF_COMMAND
  2184.     && !isstring(c_token)
  2185.     && !equals(c_token, "at")
  2186.     && !equals(c_token, "left")
  2187.     && !equals(c_token, "center")
  2188.     && !equals(c_token, "centre")
  2189.     && !equals(c_token, "right")
  2190.     && !almost_equals(c_token, "rot$ate")
  2191.     && !almost_equals(c_token, "norot$ate")
  2192.     && !equals(c_token, "font")) {
  2193.     /* must be a tag expression! */
  2194.     tag = (int) real(const_express(&a));
  2195.     if (tag <= 0)
  2196.         int_error("tag must be > zero", c_token);
  2197.     } else
  2198.     tag = assign_label_tag();    /* default next tag */
  2199.  
  2200.     /* get text */
  2201.     if (!END_OF_COMMAND && isstring(c_token)) {
  2202.     /* get text */
  2203.     quote_str(text, c_token, MAX_LINE_LEN);
  2204.     c_token++;
  2205.     set_text = TRUE;
  2206.     } else {
  2207.     text[0] = '\0';        /* default no text */
  2208.     set_text = FALSE;
  2209.     }
  2210.  
  2211.     /* get justification - what the heck, let him put it here */
  2212.     if (!END_OF_COMMAND && !equals(c_token, "at") && !equals(c_token, "font")
  2213.     && !almost_equals(c_token, "rot$ate") && !almost_equals(c_token, "norot$ate")) {
  2214.     if (almost_equals(c_token, "l$eft")) {
  2215.         just = LEFT;
  2216.     } else if (almost_equals(c_token, "c$entre")
  2217.            || almost_equals(c_token, "c$enter")) {
  2218.         just = CENTRE;
  2219.     } else if (almost_equals(c_token, "r$ight")) {
  2220.         just = RIGHT;
  2221.     } else
  2222.         int_error("bad syntax in set label", c_token);
  2223.     c_token++;
  2224.     set_just = TRUE;
  2225.     }
  2226.     /* get position */
  2227.     if (!END_OF_COMMAND && equals(c_token, "at")) {
  2228.     c_token++;
  2229.  
  2230.     get_position(&pos);
  2231.     set_position = TRUE;
  2232.     } else {
  2233.     pos.x = pos.y = pos.z = 0;
  2234.     pos.scalex = pos.scaley = pos.scalez = first_axes;
  2235.     set_position = FALSE;
  2236.     }
  2237.  
  2238.     /* get justification */
  2239.     if (!END_OF_COMMAND && !almost_equals(c_token, "rot$ate") && !almost_equals(c_token, "norot$ate") && !equals(c_token, "font")) {
  2240.     if (set_just)
  2241.         int_error("only one justification is allowed", c_token);
  2242.     if (almost_equals(c_token, "l$eft")) {
  2243.         just = LEFT;
  2244.     } else if (almost_equals(c_token, "c$entre")
  2245.            || almost_equals(c_token, "c$enter")) {
  2246.         just = CENTRE;
  2247.     } else if (almost_equals(c_token, "r$ight")) {
  2248.         just = RIGHT;
  2249.     } else
  2250.         int_error("bad syntax in set label", c_token);
  2251.  
  2252.     c_token++;
  2253.     set_just = TRUE;
  2254.     }
  2255.     /* get rotation (added by RCC) */
  2256.     if (!END_OF_COMMAND && !equals(c_token, "font")) {
  2257.     if (almost_equals(c_token, "rot$ate")) {
  2258.         rotate = TRUE;
  2259.     } else if (almost_equals(c_token, "norot$ate")) {
  2260.         rotate = FALSE;
  2261.     } else
  2262.         int_error("bad syntax in set label", c_token);
  2263.  
  2264.     c_token++;
  2265.     set_rot = TRUE;
  2266.     }
  2267.     /* get font */
  2268.     font[0] = NUL;
  2269.     set_font = FALSE;
  2270.     if (!END_OF_COMMAND && equals(c_token, "font")) {
  2271.     c_token++;
  2272.     if (END_OF_COMMAND)
  2273.         int_error("font name and size expected", c_token);
  2274.     if (isstring(c_token)) {
  2275.         quote_str(font, c_token, MAX_ID_LEN);
  2276.         /* get 'name,size', no further check */
  2277.         set_font = TRUE;
  2278.     } else
  2279.         int_error("'fontname,fontsize' expected", c_token);
  2280.  
  2281.     c_token++;
  2282.     }                /* Entry font added by DJL */
  2283.     if (!END_OF_COMMAND)
  2284.     int_error("extraenous or out-of-order arguments in set label", c_token);
  2285.  
  2286.     /* OK! add label */
  2287.     if (first_label != NULL) {    /* skip to last label */
  2288.     for (this_label = first_label; this_label != NULL;
  2289.          prev_label = this_label, this_label = this_label->next)
  2290.         /* is this the label we want? */
  2291.         if (tag <= this_label->tag)
  2292.         break;
  2293.     }
  2294.     if (this_label != NULL && tag == this_label->tag) {
  2295.     /* changing the label */
  2296.     if (set_position) {
  2297.         this_label->place = pos;
  2298.     }
  2299.     if (set_text)
  2300.         (void) strcpy(this_label->text, text);
  2301.     if (set_just)
  2302.         this_label->pos = just;
  2303.     if (set_rot)
  2304.         this_label->rotate = rotate;
  2305.     if (set_font)
  2306.         (void) strcpy(this_label->font, font);
  2307.     } else {
  2308.     /* adding the label */
  2309.     new_label = (struct text_label *)
  2310.         gp_alloc((unsigned long) sizeof(struct text_label), "label");
  2311.     if (prev_label != NULL)
  2312.         prev_label->next = new_label;    /* add it to end of list */
  2313.     else
  2314.         first_label = new_label;    /* make it start of list */
  2315.     new_label->tag = tag;
  2316.     new_label->next = this_label;
  2317.     new_label->place = pos;
  2318.     (void) strcpy(new_label->text, text);
  2319.     new_label->pos = just;
  2320.     new_label->rotate = rotate;
  2321.     (void) strcpy(new_label->font, font);
  2322.     }
  2323. }                /* Entry font added by DJL */
  2324.  
  2325. /* process 'set nolabel' command */
  2326. /* set nolabel {tag} */
  2327. static void set_nolabel()
  2328. {
  2329.     struct value a;
  2330.     struct text_label *this_label;
  2331.     struct text_label *prev_label;
  2332.     int tag;
  2333.  
  2334.     if (END_OF_COMMAND) {
  2335.     /* delete all labels */
  2336.     while (first_label != NULL)
  2337.         delete_label((struct text_label *) NULL, first_label);
  2338.     } else {
  2339.     /* get tag */
  2340.     tag = (int) real(const_express(&a));
  2341.     if (!END_OF_COMMAND)
  2342.         int_error("extraneous arguments to set nolabel", c_token);
  2343.     for (this_label = first_label, prev_label = NULL;
  2344.          this_label != NULL;
  2345.          prev_label = this_label, this_label = this_label->next) {
  2346.         if (this_label->tag == tag) {
  2347.         delete_label(prev_label, this_label);
  2348.         return;        /* exit, our job is done */
  2349.         }
  2350.     }
  2351.     int_error("label not found", c_token);
  2352.     }
  2353. }
  2354.  
  2355. /* assign a new label tag */
  2356. /* labels are kept sorted by tag number, so this is easy */
  2357. static int /* the lowest unassigned tag number */ assign_label_tag()
  2358. {
  2359.     struct text_label *this_label;
  2360.     int last = 0;        /* previous tag value */
  2361.  
  2362.     for (this_label = first_label; this_label != NULL;
  2363.      this_label = this_label->next)
  2364.     if (this_label->tag == last + 1)
  2365.         last++;
  2366.     else
  2367.         break;
  2368.  
  2369.     return (last + 1);
  2370. }
  2371.  
  2372. /* delete label from linked list started by first_label.
  2373.  * called with pointers to the previous label (prev) and the 
  2374.  * label to delete (this).
  2375.  * If there is no previous label (the label to delete is
  2376.  * first_label) then call with prev = NULL.
  2377.  */
  2378. static void delete_label(prev, this)
  2379. struct text_label *prev, *this;
  2380. {
  2381.     if (this != NULL) {        /* there really is something to delete */
  2382.     if (prev != NULL)    /* there is a previous label */
  2383.         prev->next = this->next;
  2384.     else            /* this = first_label so change first_label */
  2385.         first_label = this->next;
  2386.     free((char *) this);
  2387.     }
  2388. }
  2389.  
  2390.  
  2391. /* process a 'set arrow' command */
  2392. /* set arrow {tag} {from x,y} {to x,y} {{no}head} */
  2393. static void set_arrow()
  2394. {
  2395.     struct value a;
  2396.     struct arrow_def *this_arrow = NULL;
  2397.     struct arrow_def *new_arrow = NULL;
  2398.     struct arrow_def *prev_arrow = NULL;
  2399.     struct position spos, epos;
  2400.     struct lp_style_type loc_lp;
  2401.     int axes = FIRST_AXES;
  2402.     int tag;
  2403.     TBOOLEAN set_start, set_end, head = 1, set_axes = 0, set_line = 0;
  2404.  
  2405.     /* Init struct lp_style_type loc_lp */
  2406.     reset_lp_properties (&loc_lp);
  2407.  
  2408.     /* get tag */
  2409.     if (!END_OF_COMMAND
  2410.     && !equals(c_token, "from")
  2411.     && !equals(c_token, "to")
  2412.     && !equals(c_token, "first")
  2413.     && !equals(c_token, "second")) {
  2414.     /* must be a tag expression! */
  2415.     tag = (int) real(const_express(&a));
  2416.     if (tag <= 0)
  2417.         int_error("tag must be > zero", c_token);
  2418.     } else
  2419.     tag = assign_arrow_tag();    /* default next tag */
  2420.  
  2421.     if (!END_OF_COMMAND && equals(c_token, "first")) {
  2422.     ++c_token;
  2423.     axes = FIRST_AXES;
  2424.     set_axes = 1;
  2425.     } else if (!END_OF_COMMAND && equals(c_token, "second")) {
  2426.     ++c_token;
  2427.     axes = SECOND_AXES;
  2428.     set_axes = 1;
  2429.     }
  2430.     /* get start position */
  2431.     if (!END_OF_COMMAND && equals(c_token, "from")) {
  2432.     c_token++;
  2433.     if (END_OF_COMMAND)
  2434.         int_error("start coordinates expected", c_token);
  2435.     /* get coordinates */
  2436.     get_position(&spos);
  2437.     set_start = TRUE;
  2438.     } else {
  2439.     spos.x = spos.y = spos.z = 0;
  2440.     spos.scalex = spos.scaley = spos.scalez = first_axes;
  2441.     set_start = FALSE;
  2442.     }
  2443.  
  2444.     /* get end position */
  2445.     if (!END_OF_COMMAND && equals(c_token, "to")) {
  2446.     c_token++;
  2447.     if (END_OF_COMMAND)
  2448.         int_error("end coordinates expected", c_token);
  2449.     /* get coordinates */
  2450.     get_position(&epos);
  2451.     set_end = TRUE;
  2452.     } else {
  2453.     epos.x = epos.y = epos.z = 0;
  2454.     epos.scalex = epos.scaley = epos.scalez = first_axes;
  2455.     set_end = FALSE;
  2456.     }
  2457.  
  2458.     /* get start position - what the heck, either order is ok */
  2459.     if (!END_OF_COMMAND && equals(c_token, "from")) {
  2460.     if (set_start)
  2461.         int_error("only one 'from' is allowed", c_token);
  2462.     c_token++;
  2463.     if (END_OF_COMMAND)
  2464.         int_error("start coordinates expected", c_token);
  2465.     /* get coordinates */
  2466.     get_position(&spos);
  2467.     set_start = TRUE;
  2468.     }
  2469.     if (!END_OF_COMMAND && equals(c_token, "nohead")) {
  2470.     c_token++;
  2471.     head = 0;
  2472.     }
  2473.     if (!END_OF_COMMAND && equals(c_token, "head")) {
  2474.     c_token++;
  2475.     head = 1;
  2476.     }
  2477.     set_line = 1;
  2478.  
  2479.     /* pick up a line spec - allow ls, but no point. */
  2480.     LP_PARSE(loc_lp, 1, 0, 0, 0);
  2481.     loc_lp.pointflag = 0;    /* standard value for arrows, don't use points */
  2482.  
  2483.     if (!END_OF_COMMAND)
  2484.     int_error("extraneous or out-of-order arguments in set arrow", c_token);
  2485.  
  2486.     /* OK! add arrow */
  2487.     if (first_arrow != NULL) {    /* skip to last arrow */
  2488.     for (this_arrow = first_arrow; this_arrow != NULL;
  2489.          prev_arrow = this_arrow, this_arrow = this_arrow->next)
  2490.         /* is this the arrow we want? */
  2491.         if (tag <= this_arrow->tag)
  2492.         break;
  2493.     }
  2494.     if (this_arrow != NULL && tag == this_arrow->tag) {
  2495.     /* changing the arrow */
  2496.     if (set_start) {
  2497.         this_arrow->start = spos;
  2498.     }
  2499.     if (set_end) {
  2500.         this_arrow->end = epos;
  2501.     }
  2502.     this_arrow->head = head;
  2503.     if (set_line) {
  2504.         this_arrow->lp_properties = loc_lp;
  2505.     }
  2506.     } else {
  2507.     /* adding the arrow */
  2508.     new_arrow = (struct arrow_def *)
  2509.         gp_alloc((unsigned long) sizeof(struct arrow_def), "arrow");
  2510.     if (prev_arrow != NULL)
  2511.         prev_arrow->next = new_arrow;    /* add it to end of list */
  2512.     else
  2513.         first_arrow = new_arrow;    /* make it start of list */
  2514.     new_arrow->tag = tag;
  2515.     new_arrow->next = this_arrow;
  2516.     new_arrow->start = spos;
  2517.     new_arrow->end = epos;
  2518.     new_arrow->head = head;
  2519.     new_arrow->lp_properties = loc_lp;
  2520.     }
  2521. }
  2522.  
  2523. /* process 'set noarrow' command */
  2524. /* set noarrow {tag} */
  2525. static void set_noarrow()
  2526. {
  2527.     struct value a;
  2528.     struct arrow_def *this_arrow;
  2529.     struct arrow_def *prev_arrow;
  2530.     int tag;
  2531.  
  2532.     if (END_OF_COMMAND) {
  2533.     /* delete all arrows */
  2534.     while (first_arrow != NULL)
  2535.         delete_arrow((struct arrow_def *) NULL, first_arrow);
  2536.     } else {
  2537.     /* get tag */
  2538.     tag = (int) real(const_express(&a));
  2539.     if (!END_OF_COMMAND)
  2540.         int_error("extraneous arguments to set noarrow", c_token);
  2541.     for (this_arrow = first_arrow, prev_arrow = NULL;
  2542.          this_arrow != NULL;
  2543.          prev_arrow = this_arrow, this_arrow = this_arrow->next) {
  2544.         if (this_arrow->tag == tag) {
  2545.         delete_arrow(prev_arrow, this_arrow);
  2546.         return;        /* exit, our job is done */
  2547.         }
  2548.     }
  2549.     int_error("arrow not found", c_token);
  2550.     }
  2551. }
  2552.  
  2553. /* assign a new arrow tag */
  2554. /* arrows are kept sorted by tag number, so this is easy */
  2555. static int /* the lowest unassigned tag number */ assign_arrow_tag()
  2556. {
  2557.     struct arrow_def *this_arrow;
  2558.     int last = 0;        /* previous tag value */
  2559.  
  2560.     for (this_arrow = first_arrow; this_arrow != NULL;
  2561.      this_arrow = this_arrow->next)
  2562.     if (this_arrow->tag == last + 1)
  2563.         last++;
  2564.     else
  2565.         break;
  2566.  
  2567.     return (last + 1);
  2568. }
  2569.  
  2570. /* delete arrow from linked list started by first_arrow.
  2571.  * called with pointers to the previous arrow (prev) and the 
  2572.  * arrow to delete (this).
  2573.  * If there is no previous arrow (the arrow to delete is
  2574.  * first_arrow) then call with prev = NULL.
  2575.  */
  2576. static void delete_arrow(prev, this)
  2577. struct arrow_def *prev, *this;
  2578. {
  2579.     if (this != NULL) {        /* there really is something to delete */
  2580.     if (prev != NULL)    /* there is a previous arrow */
  2581.         prev->next = this->next;
  2582.     else            /* this = first_arrow so change first_arrow */
  2583.         first_arrow = this->next;
  2584.     free((char *) this);
  2585.     }
  2586. }
  2587.  
  2588. /* ======================================================== */
  2589. /* process a 'set linestyle' command */
  2590. /* set linestyle {tag} {linetype n} {linewidth x} {pointtype n} {pointsize x} */
  2591. static void set_linestyle()
  2592. {
  2593.     struct value a;
  2594.     struct linestyle_def *this_linestyle = NULL;
  2595.     struct linestyle_def *new_linestyle = NULL;
  2596.     struct linestyle_def *prev_linestyle = NULL;
  2597.     struct lp_style_type loc_lp;
  2598.     int tag;
  2599.  
  2600.     /* Init struct lp_style_type loc_lp */
  2601.     reset_lp_properties (&loc_lp);
  2602.  
  2603.     /* get tag */
  2604.     if (!END_OF_COMMAND) {
  2605.     /* must be a tag expression! */
  2606.     tag = (int) real(const_express(&a));
  2607.     if (tag <= 0)
  2608.         int_error("tag must be > zero", c_token);
  2609.     } else
  2610.     tag = assign_linestyle_tag();    /* default next tag */
  2611.  
  2612.     /* pick up a line spec : dont allow ls, do allow point type
  2613.      * default to same line type = point type = tag
  2614.      */
  2615.     LP_PARSE(loc_lp, 0, 1, tag - 1, tag - 1);
  2616.  
  2617.     if (!END_OF_COMMAND)
  2618.     int_error("extraneous or out-of-order arguments in set linestyle", c_token);
  2619.  
  2620.     /* OK! add linestyle */
  2621.     if (first_linestyle != NULL) {    /* skip to last linestyle */
  2622.     for (this_linestyle = first_linestyle; this_linestyle != NULL;
  2623.          prev_linestyle = this_linestyle, this_linestyle = this_linestyle->next)
  2624.         /* is this the linestyle we want? */
  2625.         if (tag <= this_linestyle->tag)
  2626.         break;
  2627.     }
  2628.     if (this_linestyle != NULL && tag == this_linestyle->tag) {
  2629.     /* changing the linestyle */
  2630.     this_linestyle->lp_properties = loc_lp;
  2631.     } else {
  2632.     /* adding the linestyle */
  2633.     new_linestyle = (struct linestyle_def *)
  2634.         gp_alloc((unsigned long) sizeof(struct linestyle_def), "linestyle");
  2635.     if (prev_linestyle != NULL)
  2636.         prev_linestyle->next = new_linestyle;    /* add it to end of list */
  2637.     else
  2638.         first_linestyle = new_linestyle;    /* make it start of list */
  2639.     new_linestyle->tag = tag;
  2640.     new_linestyle->next = this_linestyle;
  2641.     new_linestyle->lp_properties = loc_lp;
  2642.     }
  2643. }
  2644.  
  2645. /* process 'set nolinestyle' command */
  2646. /* set nolinestyle {tag} */
  2647. static void set_nolinestyle()
  2648. {
  2649.     struct value a;
  2650.     struct linestyle_def *this, *prev;
  2651.     int tag;
  2652.  
  2653.     if (END_OF_COMMAND) {
  2654.     /* delete all linestyles */
  2655.     while (first_linestyle != NULL)
  2656.         delete_linestyle((struct linestyle_def *) NULL, first_linestyle);
  2657.     } else {
  2658.     /* get tag */
  2659.     tag = (int) real(const_express(&a));
  2660.     if (!END_OF_COMMAND)
  2661.         int_error("extraneous arguments to set nolinestyle", c_token);
  2662.     for (this = first_linestyle, prev = NULL;
  2663.          this != NULL;
  2664.          prev = this, this = this->next) {
  2665.         if (this->tag == tag) {
  2666.         delete_linestyle(prev, this);
  2667.         return;        /* exit, our job is done */
  2668.         }
  2669.     }
  2670.     int_error("linestyle not found", c_token);
  2671.     }
  2672. }
  2673.  
  2674. /* assign a new linestyle tag */
  2675. /* linestyles are kept sorted by tag number, so this is easy */
  2676. static int /* the lowest unassigned tag number */ assign_linestyle_tag()
  2677. {
  2678.     struct linestyle_def *this;
  2679.     int last = 0;        /* previous tag value */
  2680.  
  2681.     for (this = first_linestyle; this != NULL; this = this->next)
  2682.     if (this->tag == last + 1)
  2683.         last++;
  2684.     else
  2685.         break;
  2686.  
  2687.     return (last + 1);
  2688. }
  2689.  
  2690. /* delete linestyle from linked list started by first_linestyle.
  2691.  * called with pointers to the previous linestyle (prev) and the 
  2692.  * linestyle to delete (this).
  2693.  * If there is no previous linestyle (the linestyle to delete is
  2694.  * first_linestyle) then call with prev = NULL.
  2695.  */
  2696. static void delete_linestyle(prev, this)
  2697. struct linestyle_def *prev, *this;
  2698. {
  2699.     if (this != NULL) {        /* there really is something to delete */
  2700.     if (prev != NULL)    /* there is a previous linestyle */
  2701.         prev->next = this->next;
  2702.     else            /* this = first_linestyle so change first_linestyle */
  2703.         first_linestyle = this->next;
  2704.     free((char *) this);
  2705.     }
  2706. }
  2707.  
  2708. /*
  2709.  * auxiliary functions for the `set linestyle` command
  2710.  */
  2711.  
  2712. void lp_use_properties(lp, tag, pointflag)
  2713. struct lp_style_type *lp;
  2714. int tag, pointflag;
  2715. {
  2716.     /*  This function looks for a linestyle defined by 'tag' and copies
  2717.      *  its data into the structure 'lp'.
  2718.      *
  2719.      *  If 'pointflag' equals ZERO, the properties belong to a linestyle
  2720.      *  used with arrows.  In this case no point properties will be
  2721.      *  passed to the terminal (cf. function 'term_apply_lp_properties' below).
  2722.      */
  2723.  
  2724.     struct linestyle_def *this;
  2725.  
  2726.     this = first_linestyle;
  2727.     while (this != NULL) {
  2728.     if (this->tag == tag) {
  2729.         *lp = this->lp_properties;
  2730.         lp->pointflag = pointflag;
  2731.         return;
  2732.     } else {
  2733.         this = this->next;
  2734.     }
  2735.     }
  2736.  
  2737.     /* tag not found: */
  2738.     int_error("linestyle not found", NO_CARET);
  2739. }
  2740.  
  2741. /* ======================================================== */
  2742.  
  2743. enum PLOT_STYLE /* not static; used by command.c */ get_style()
  2744. {
  2745.     register enum PLOT_STYLE ps = LINES;    /* HBB: initial value, for 'gcc -W} */
  2746.  
  2747.     c_token++;
  2748.     if (almost_equals(c_token, "l$ines"))
  2749.     ps = LINES;
  2750.     else if (almost_equals(c_token, "i$mpulses"))
  2751.     ps = IMPULSES;
  2752.     else if (almost_equals(c_token, "p$oints"))
  2753.     ps = POINTSTYLE;
  2754.     else if (almost_equals(c_token, "linesp$oints") || equals(c_token, "lp"))
  2755.     ps = LINESPOINTS;
  2756.     else if (almost_equals(c_token, "d$ots"))
  2757.     ps = DOTS;
  2758.     else if (almost_equals(c_token, "ye$rrorbars"))
  2759.     ps = YERRORBARS;
  2760.     else if (almost_equals(c_token, "e$rrorbars"))
  2761.     ps = YERRORBARS;
  2762.     else if (almost_equals(c_token, "xe$rrorbars"))
  2763.     ps = XERRORBARS;
  2764.     else if (almost_equals(c_token, "xye$rrorbars"))
  2765.     ps = XYERRORBARS;
  2766.     else if (almost_equals(c_token, "boxes"))
  2767.     ps = BOXES;
  2768.     else if (almost_equals(c_token, "boxer$rorbars"))
  2769.     ps = BOXERROR;
  2770.     else if (almost_equals(c_token, "boxx$yerrorbars"))
  2771.     ps = BOXXYERROR;
  2772.     else if (almost_equals(c_token, "st$eps"))
  2773.     ps = STEPS;
  2774.     else if (almost_equals(c_token, "fs$teps"))
  2775.     ps = FSTEPS;
  2776.     else if (almost_equals(c_token, "his$teps"))
  2777.     ps = HISTEPS;
  2778.     else if (almost_equals(c_token, "vec$tor"))        /* HBB: minor cosmetic change */
  2779.     ps = VECTOR;
  2780.     else if (almost_equals(c_token, "fin$ancebars"))
  2781.     ps = FINANCEBARS;
  2782.     else if (almost_equals(c_token, "can$dlesticks"))
  2783.     ps = CANDLESTICKS;
  2784.     else {
  2785.     int_error("expecting 'lines', 'points', 'linespoints', 'dots', 'impulses',\n\
  2786.         'yerrorbars', 'xerrorbars', 'xyerrorbars', 'steps', 'fsteps', 'histeps',\n\
  2787.         'boxes', 'boxerrorbars', 'boxxyerrorbars', 'vector', 'financebars', 'candlesticks'", c_token);
  2788.     return LINES;        /* keep gcc -Wuninitialised happy */
  2789.     }
  2790.     c_token++;
  2791.     return (ps);
  2792. }
  2793.  
  2794. /* For set [xy]tics... command */
  2795. static void load_tics(axis, tdef)
  2796. int axis;
  2797. struct ticdef *tdef;        /* change this ticdef */
  2798. {
  2799.     if (equals(c_token, "(")) {    /* set : TIC_USER */
  2800.     c_token++;
  2801.     load_tic_user(axis, tdef);
  2802.     } else {            /* series : TIC_SERIES */
  2803.     load_tic_series(axis, tdef);
  2804.     }
  2805. }
  2806.  
  2807. /* load TIC_USER definition */
  2808. /* (tic[,tic]...)
  2809.  * where tic is ["string"] value
  2810.  * Left paren is already scanned off before entry.
  2811.  */
  2812. static void load_tic_user(axis, tdef)
  2813. int axis;
  2814. struct ticdef *tdef;
  2815. {
  2816.     struct ticmark *list = NULL;    /* start of list */
  2817.     struct ticmark *last = NULL;    /* end of list */
  2818.     struct ticmark *tic = NULL;    /* new ticmark */
  2819.     char temp_string[MAX_LINE_LEN];
  2820.  
  2821.     while (!END_OF_COMMAND) {
  2822.     /* parse a new ticmark */
  2823.     tic = (struct ticmark *) gp_alloc((unsigned long) sizeof(struct ticmark), (char *) NULL);
  2824.     if (tic == (struct ticmark *) NULL) {
  2825.         free_marklist(list);
  2826.         int_error("out of memory for tic mark", c_token);
  2827.     }
  2828.     /* syntax is  (  ['format'] value , ... )
  2829.      * but for timedata, the value itself is a string, which
  2830.      * complicates things somewhat
  2831.      */
  2832.  
  2833.     /* has a string with it? */
  2834.     if (isstring(c_token) &&
  2835.         (datatype[axis] != TIME || isstring(c_token + 1))) {
  2836.         quote_str(temp_string, c_token, MAX_LINE_LEN);
  2837.         tic->label = gp_alloc((unsigned long) strlen(temp_string) + 1, "tic label");
  2838.         (void) strcpy(tic->label, temp_string);
  2839.         c_token++;
  2840.     } else
  2841.         tic->label = NULL;
  2842.  
  2843.     /* in any case get the value */
  2844.     GET_NUM_OR_TIME(tic->position, axis);
  2845.     tic->next = NULL;
  2846.  
  2847.     /* append to list */
  2848.     if (list == NULL)
  2849.         last = list = tic;    /* new list */
  2850.     else {            /* append to list */
  2851.         last->next = tic;
  2852.         last = tic;
  2853.     }
  2854.  
  2855.     /* expect "," or ")" here */
  2856.     if (!END_OF_COMMAND && equals(c_token, ","))
  2857.         c_token++;        /* loop again */
  2858.     else
  2859.         break;        /* hopefully ")" */
  2860.     }
  2861.  
  2862.     if (END_OF_COMMAND || !equals(c_token, ")")) {
  2863.     free_marklist(list);
  2864.     int_error("expecting right parenthesis )", c_token);
  2865.     }
  2866.     c_token++;
  2867.  
  2868.     /* successful list */
  2869.     if (tdef->type == TIC_USER) {
  2870.     /* remove old list */
  2871.     /* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
  2872.     free_marklist(tdef->def.user);
  2873.     tdef->def.user = NULL;
  2874.     }
  2875.     tdef->type = TIC_USER;
  2876.     tdef->def.user = list;
  2877. }
  2878.  
  2879. static void free_marklist(list)
  2880. struct ticmark *list;
  2881. {
  2882.     register struct ticmark *freeable;
  2883.  
  2884.     while (list != NULL) {
  2885.     freeable = list;
  2886.     list = list->next;
  2887.     if (freeable->label != NULL)
  2888.         free((char *) freeable->label);
  2889.     free((char *) freeable);
  2890.     }
  2891. }
  2892.  
  2893. /* load TIC_SERIES definition */
  2894. /* [start,]incr[,end] */
  2895. static void load_tic_series(axis, tdef)
  2896. int axis;
  2897. struct ticdef *tdef;
  2898. {
  2899.     double start, incr, end;
  2900.     int incr_token;
  2901.  
  2902.     GET_NUM_OR_TIME(start, axis);
  2903.  
  2904.     if (!equals(c_token, ",")) {
  2905.     /* only step specified */
  2906.     incr = start;
  2907.     start = -VERYLARGE;
  2908.     end = VERYLARGE;
  2909.     } else {
  2910.  
  2911.     c_token++;
  2912.  
  2913.     incr_token = c_token;
  2914.     GET_NUM_OR_TIME(incr, axis);
  2915.  
  2916.     if (END_OF_COMMAND)
  2917.         end = VERYLARGE;
  2918.     else {
  2919.         if (!equals(c_token, ","))
  2920.         int_error("expecting comma to separate incr,end", c_token);
  2921.         c_token++;
  2922.         GET_NUM_OR_TIME(end, axis);
  2923.     }
  2924.     if (!END_OF_COMMAND)
  2925.         int_error("tic series is defined by [start,]increment[,end]", c_token);
  2926.  
  2927.     if (start < end && incr <= 0)
  2928.         int_error("increment must be positive", incr_token);
  2929.     if (start > end && incr >= 0)
  2930.         int_error("increment must be negative", incr_token);
  2931.     if (start > end) {
  2932.         /* put in order */
  2933.         double numtics;
  2934.         numtics = floor((end * (1 + SIGNIF) - start) / incr);
  2935.         end = start;
  2936.         start = end + numtics * incr;
  2937.         incr = -incr;
  2938. /*
  2939.    double temp = start;
  2940.    start = end;
  2941.    end = temp;
  2942.    incr = -incr;
  2943.  */
  2944.     }
  2945.     }
  2946.  
  2947.     if (tdef->type == TIC_USER) {
  2948.     /* remove old list */
  2949.     /* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
  2950.     free_marklist(tdef->def.user);
  2951.     tdef->def.user = NULL;
  2952.     }
  2953.     tdef->type = TIC_SERIES;
  2954.     tdef->def.series.start = start;
  2955.     tdef->def.series.incr = incr;
  2956.     tdef->def.series.end = end;
  2957. }
  2958.  
  2959. static void load_offsets(a, b, c, d)
  2960. double *a, *b, *c, *d;
  2961. {
  2962.     struct value t;
  2963.  
  2964.     *a = real(const_express(&t));    /* loff value */
  2965.     if (!equals(c_token, ","))
  2966.     return;
  2967.  
  2968.     c_token++;
  2969.     *b = real(const_express(&t));    /* roff value */
  2970.     if (!equals(c_token, ","))
  2971.     return;
  2972.  
  2973.     c_token++;
  2974.     *c = real(const_express(&t));    /* toff value */
  2975.     if (!equals(c_token, ","))
  2976.     return;
  2977.  
  2978.     c_token++;
  2979.     *d = real(const_express(&t));    /* boff value */
  2980. }
  2981.  
  2982. TBOOLEAN            /* new value for autosc */
  2983. load_range(axis, a, b, autosc)        /* also used by command.c */
  2984. int axis;
  2985. double *a, *b;
  2986. TBOOLEAN autosc;
  2987. {
  2988.     if (equals(c_token, "]"))
  2989.     return (autosc);
  2990.     if (END_OF_COMMAND) {
  2991.     int_error("starting range value or ':' or 'to' expected", c_token);
  2992.     } else if (!equals(c_token, "to") && !equals(c_token, ":")) {
  2993.     if (equals(c_token, "*")) {
  2994.         autosc |= 1;
  2995.         c_token++;
  2996.     } else {
  2997.         GET_NUM_OR_TIME(*a, axis);
  2998.         autosc &= 2;
  2999.     }
  3000.     }
  3001.     if (!equals(c_token, "to") && !equals(c_token, ":"))
  3002.     int_error("':' or keyword 'to' expected", c_token);
  3003.     c_token++;
  3004.     if (!equals(c_token, "]")) {
  3005.     if (equals(c_token, "*")) {
  3006.         autosc |= 2;
  3007.         c_token++;
  3008.     } else {
  3009.         GET_NUM_OR_TIME(*b, axis);
  3010.         autosc &= 1;
  3011.     }
  3012.     }
  3013.     return (autosc);
  3014. }
  3015.  
  3016. /* return 1 if format looks like a numeric format
  3017.  * ie more than one %{efg}, or %something-else
  3018.  */
  3019.  
  3020. static int looks_like_numeric(format)
  3021. char *format;
  3022. {
  3023.     if (!(format = strchr(format, '%')))
  3024.     return 0;
  3025.  
  3026.     while (++format, (*format >= '0' && *format <= '9') || *format == '.');
  3027.  
  3028.     return (*format == 'f' || *format == 'g' || *format == 'e');
  3029. }
  3030.  
  3031.  
  3032. /* parse a position of the form
  3033.  *    [coords] x, [coords] y {,[coords] z}
  3034.  * where coords is one of first,second.graph,screen
  3035.  * if first or second, we need to take datatype into account
  3036.  * mixed co-ordinates are for specialists, but it's not particularly
  3037.  * hard to implement...
  3038.  */
  3039.  
  3040. #define GET_NUMBER_OR_TIME(store,axes,axis) \
  3041. do{if (axes >= 0 && datatype[axes+axis] == TIME && isstring(c_token) ) { \
  3042.     char ss[80]; struct tm tm; \
  3043.     quote_str(ss,c_token, 80); ++c_token; \
  3044.     if (gstrptime(ss,timefmt,&tm)) store = (double) gtimegm(&tm); \
  3045.    } else {\
  3046.     struct value value; \
  3047.     store = real(const_express(&value));\
  3048.   }}while(0)
  3049.  
  3050.  
  3051. /* get_position_type - for use by get_position().
  3052.  * parses first/second/graph/screen keyword
  3053.  */
  3054.  
  3055. static void get_position_type(type, axes)
  3056. enum position_type *type;
  3057. int *axes;
  3058. {
  3059.     if (almost_equals(c_token, "fir$st")) {
  3060.     ++c_token;
  3061.     *type = first_axes;
  3062.     } else if (almost_equals(c_token, "sec$ond")) {
  3063.     ++c_token;
  3064.     *type = second_axes;
  3065.     } else if (almost_equals(c_token, "gr$aph")) {
  3066.     ++c_token;
  3067.     *type = graph;
  3068.     } else if (almost_equals(c_token, "sc$reen")) {
  3069.     ++c_token;
  3070.     *type = screen;
  3071.     }
  3072.     switch (*type) {
  3073.     case first_axes:
  3074.     *axes = FIRST_AXES;
  3075.     return;
  3076.     case second_axes:
  3077.     *axes = SECOND_AXES;
  3078.     return;
  3079.     default:
  3080.     *axes = (-1);
  3081.     return;
  3082.     }
  3083. }
  3084.  
  3085. /* get_position() - reads a position for label,arrow,key,... */
  3086.  
  3087. static void get_position(pos)
  3088. struct position *pos;
  3089. {
  3090.     int axes;
  3091.     enum position_type type = first_axes;
  3092.  
  3093.     get_position_type(&type, &axes);
  3094.     pos->scalex = type;
  3095.     GET_NUMBER_OR_TIME(pos->x, axes, FIRST_X_AXIS);
  3096.     if (!equals(c_token, ","))
  3097.     int_error("Expected comma", c_token);
  3098.     ++c_token;
  3099.     get_position_type(&type, &axes);
  3100.     pos->scaley = type;
  3101.     GET_NUMBER_OR_TIME(pos->y, axes, FIRST_Y_AXIS);
  3102.  
  3103.     /* z is not really allowed for a screen co-ordinate, but keep it simple ! */
  3104.     if (equals(c_token, ",")) {
  3105.     ++c_token;
  3106.     get_position_type(&type, &axes);
  3107.     pos->scalez = type;
  3108.     GET_NUMBER_OR_TIME(pos->z, axes, FIRST_Z_AXIS);
  3109.     } else {
  3110.     pos->z = 0;
  3111.     pos->scalez = type;    /* same as y */
  3112.     }
  3113. }
  3114.  
  3115. static void set_lp_properties(arg, allow_points, lt, pt, lw, ps)
  3116. struct lp_style_type *arg;
  3117. int allow_points, lt, pt;
  3118. double lw, ps;
  3119. {
  3120.     arg->pointflag = allow_points;
  3121.     arg->l_type = lt;
  3122.     arg->p_type = pt;
  3123.     arg->l_width = lw;
  3124.     arg->p_size = ps;
  3125. }
  3126.  
  3127. static void reset_lp_properties(arg)
  3128. struct lp_style_type *arg;
  3129. {
  3130.     /* See plot.h for struct lp_style_type */
  3131.     arg->pointflag = arg->l_type = arg->p_type = 0;
  3132.     arg->l_width = arg->p_size = 1.0;
  3133. }
  3134.  
  3135. static void set_locale(lcl)
  3136. char *lcl;
  3137. {
  3138. #ifndef NO_LOCALE_H
  3139.     int i;
  3140.     struct tm tm;
  3141.  
  3142.     if (setlocale(LC_TIME, lcl))
  3143.     safe_strncpy(cur_locale, lcl, sizeof(cur_locale));
  3144.     else
  3145.     int_error("Locale not available", c_token);
  3146.  
  3147.     /* we can do a *lot* better than this ; eg use system functions
  3148.      * where available; create values on first use, etc
  3149.      */
  3150.     memset(&tm, 0, sizeof(struct tm));
  3151.     for (i = 0; i < 7; ++i) {
  3152.     tm.tm_wday = i;        /* hope this enough */
  3153.     strftime(full_day_names[i], sizeof(full_day_names[i]), "%A", &tm);
  3154.     strftime(abbrev_day_names[i], sizeof(abbrev_day_names[i]), "%a", &tm);
  3155.     }
  3156.     for (i = 0; i < 12; ++i) {
  3157.     tm.tm_mon = i;        /* hope this enough */
  3158.     strftime(full_month_names[i], sizeof(full_month_names[i]), "%B", &tm);
  3159.     strftime(abbrev_month_names[i], sizeof(abbrev_month_names[i]), "%b", &tm);
  3160.     }
  3161. #else
  3162.     safe_strncpy(cur_locale, lcl, sizeof(cur_locale));
  3163. #endif /* NO_LOCALE_H */
  3164. }
  3165.